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 5f14f478c36..47f70f3edcb 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 @@ -7467,6 +7467,95 @@ public class AST2CPPTests extends AST2BaseTest { ICPPMethod m= bh.assertNonProblem("t<1>", 1); assertTrue(m.isInline()); } - + + // class B {}; + // class A { + // public: + // A() {}; + // A(B c) {}; + // }; + // + // class C : B { + // public: + // operator A() {} + // }; + // void foo(A a) {} + // void test() { + // C c= *new C(); + // foo(c); + // } + public void testUserdefinedConversion_222444a() throws Exception { + final String code = getAboveComment(); + parseAndCheckBindings(code, ParserLanguage.CPP); + } + + // class From {}; + // class To1 { + // public: + // To1(...) {} + // }; + // class To2 { + // public: + // To2(From f) {} + // }; + // class To3 { + // public: + // To3(From f, int a=0) {} + // }; + // + // void x1(To1 t) {} + // void x2(To2 t) {} + // void x3(To3 t) {} + // void test() { + // From f; + // x1(f); + // x2(f); + // x3(f); + // } + public void testUserdefinedConversion_222444b() throws Exception { + final String code = getAboveComment(); + parseAndCheckBindings(code, ParserLanguage.CPP); + } + + // class A {}; + // class B : public A {}; + // + // class C { + // public: + // operator const B() { return *new B();} + // }; + // + // void foo(A a) {} + // + // void refs() { + // C c= *new C(); + // const C cc= *new C(); + // foo(c); + // foo(cc); + // } + public void testUserdefinedConversion_222444c() throws Exception { + final String code = getAboveComment(); + BindingAssertionHelper bh= new BindingAssertionHelper(code, true); + bh.assertNonProblem("foo(c);", 3); + bh.assertProblem("foo(cc);", 3); + } + + // class ULONGLONG { + // public : + // ULONGLONG ( unsigned long long val ) {} + // friend bool operator == ( const ULONGLONG & , const int ) { return true; } + // }; + // enum E {A, B, C}; + // int main() { + // return B == 23; + // } + public void testInvalidOverload_291409() throws Exception { + final String code = getAboveComment(); + IASTTranslationUnit tu= parseAndCheckBindings(code, ParserLanguage.CPP); + IASTFunctionDefinition fdef= getDeclaration(tu, 2); + IASTReturnStatement stmt= getStatement(fdef, 0); + IASTImplicitNameOwner no= (IASTImplicitNameOwner) stmt.getReturnValue(); + assertEquals(0, no.getImplicitNames().length); + } } diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2Tests.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2Tests.java index 57b9e3c4b97..7a76a99536e 100644 --- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2Tests.java +++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2Tests.java @@ -4757,7 +4757,7 @@ public class AST2Tests extends AST2BaseTest { // foo(b); // foo(c); // } - public void _testBug222444_a() throws Exception { + public void testBug222444_a() throws Exception { BindingAssertionHelper ba= new BindingAssertionHelper(getAboveComment(), true); ICPPFunction foo1= ba.assertNonProblem("foo(b", 3, ICPPFunction.class); ICPPFunction foo2= ba.assertNonProblem("foo(c", 3, ICPPFunction.class); @@ -4778,7 +4778,27 @@ public class AST2Tests extends AST2BaseTest { // // foo(c); // } - public void _testBug222444_b() throws Exception { + public void testBug222444_b() throws Exception { + BindingAssertionHelper ba= new BindingAssertionHelper(getAboveComment(), true); + ICPPFunction foo2= ba.assertNonProblem("foo(c", 3, ICPPFunction.class); + } + + // class A {}; + // class B : public A {}; + // + // class C { + // public: + // operator const B&() { return *new B();} + // }; + // + // void foo(A a) {} + // + // void refs() { + // C c= *new C(); + // + // foo(c); + // } + public void testBug222444_c() throws Exception { BindingAssertionHelper ba= new BindingAssertionHelper(getAboveComment(), true); ICPPFunction foo2= ba.assertNonProblem("foo(c", 3, ICPPFunction.class); } 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 33a341ca5d0..e109bf5ea3f 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 @@ -2075,7 +2075,9 @@ public class CPPSemantics { implicitType = getImplicitType((ICPPMethod) fn, ftype.isConst(), ftype.isVolatile()); if (data.firstArgIsImpliedMethodArg) { argTypes = ArrayUtil.removeFirst(argTypes); - args = ArrayUtil.removeFirst(args); + if (args != null) { + args = ArrayUtil.removeFirst(args); + } } } @@ -2088,8 +2090,8 @@ public class CPPSemantics { } else { result= new FunctionCost(fn, sourceLen+1); + boolean sourceIsLValue= true; final IType thisType = data.getImpliedObjectArgument(); - if (fn instanceof ICPPMethod && (((ICPPMethod) fn).isDestructor() || ASTInternal.isStatic(fn, false))) { // 13.3.1-4 for static member functions, the implicit object parameter always matches, no cost @@ -2101,12 +2103,12 @@ public class CPPSemantics { } else { if (CPPTemplates.isDependentType(implicitType)) return CONTAINS_DEPENDENT_TYPES; - cost = Conversions.checkImplicitConversionSequence(null, thisType, implicitType, UDCMode.noUDC, true); + cost = Conversions.checkImplicitConversionSequence(sourceIsLValue, thisType, implicitType, UDCMode.noUDC, true); } if (cost.getRank() == Rank.NO_MATCH) return null; - result.setCost(k++, cost); + result.setCost(k++, cost, sourceIsLValue); } final UDCMode udc = allowUDC ? UDCMode.deferUDC : UDCMode.noUDC; @@ -2116,6 +2118,7 @@ public class CPPSemantics { return null; final IASTExpression arg= args != null && j < args.length ? args[j] : null; + final boolean sourceIsLValue = arg != null && !CPPVisitor.isRValue(arg); IType paramType; if (j < paramTypes.length) { @@ -2124,7 +2127,7 @@ public class CPPSemantics { paramType= VOID_TYPE; } else { cost = new Cost(argType, null, Rank.ELLIPSIS_CONVERSION); - result.setCost(k++, cost); + result.setCost(k++, cost, sourceIsLValue); continue; } @@ -2133,17 +2136,17 @@ public class CPPSemantics { } else { if (CPPTemplates.isDependentType(paramType)) return CONTAINS_DEPENDENT_TYPES; - cost = Conversions.checkImplicitConversionSequence(arg, argType, paramType, udc, false); + cost = Conversions.checkImplicitConversionSequence(sourceIsLValue, argType, paramType, udc, false); } if (cost.getRank() == Rank.NO_MATCH) return null; - result.setCost(k++, cost); + result.setCost(k++, cost, sourceIsLValue); } return result; } - private static IType getImplicitType(ICPPMethod m, final boolean isConst, final boolean isVolatile) + static IType getImplicitType(ICPPMethod m, final boolean isConst, final boolean isVolatile) throws DOMException { IType implicitType; ICPPClassType owner= m.getClassOwner(); @@ -2495,7 +2498,7 @@ public class CPPSemantics { IASTFieldReference innerFR= new CPPASTFieldReference(arw, new CPPASTIdExpression(x)); innerFR.setParent(fieldReference); // connect to the AST - ICPPFunction op = findOverloadedOperator(innerFR, args, uTemp, operatorName, false); + ICPPFunction op = findOverloadedOperator(innerFR, args, uTemp, operatorName, NonMemberMode.none); if (op == null) break; @@ -2523,7 +2526,7 @@ public class CPPSemantics { IASTExpression[] args = {exp.getArrayExpression(), exp.getSubscriptExpression()}; IType type1 = exp.getArrayExpression().getExpressionType(); IType ultimateType1 = SemanticUtil.getUltimateTypeUptoPointers(type1); - return findOverloadedOperator(exp, args, ultimateType1, name, false); + return findOverloadedOperator(exp, args, ultimateType1, name, NonMemberMode.none); } @@ -2545,7 +2548,7 @@ public class CPPSemantics { args = new IASTExpression[] { exp.getFunctionNameExpression() }; } - return findOverloadedOperator(exp, args, type, name, false); + return findOverloadedOperator(exp, args, type, name, NonMemberMode.none); } public static ICPPFunction findOverloadedOperator(ICPPASTNewExpression exp) { @@ -2571,14 +2574,14 @@ public class CPPSemantics { } IASTExpression[] argArray = args.toArray(new IASTExpression[args.size()]); - return findOverloadedOperator(exp, argArray, type, op.toCharArray(), true); + return findOverloadedOperator(exp, argArray, type, op.toCharArray(), NonMemberMode.all); } public static ICPPFunction findOverloadedOperator(ICPPASTDeleteExpression exp) { OverloadableOperator op = OverloadableOperator.fromDeleteExpression(exp); IASTExpression[] args = { exp.getOperand() }; IType classType = getNestedClassType(exp); - return findOverloadedOperator(exp, args, classType, op.toCharArray(), true); + return findOverloadedOperator(exp, args, classType, op.toCharArray(), NonMemberMode.all); } private static ICPPClassType getNestedClassType(ICPPASTDeleteExpression exp) { @@ -2645,7 +2648,7 @@ public class CPPSemantics { if (!isUserDefined(type)) return null; - return findOverloadedOperator(exp, args, type, op.toCharArray(), true); + return findOverloadedOperator(exp, args, type, op.toCharArray(), NonMemberMode.limited); } public static ICPPFunction findOverloadedOperator(IASTBinaryExpression exp) { @@ -2656,7 +2659,7 @@ public class CPPSemantics { IType op1type = SemanticUtil.getUltimateTypeUptoPointers(exp.getOperand1().getExpressionType()); IASTExpression[] args = new IASTExpression[] { exp.getOperand1(), exp.getOperand2() } ; - boolean lookupNonMember = false; + NonMemberMode lookupNonMember = NonMemberMode.none; if (exp.getOperator() != IASTBinaryExpression.op_assign) { IType op2type = SemanticUtil.getUltimateTypeUptoPointers(exp.getOperand2().getExpressionType()); if (op2type instanceof IProblemBinding) @@ -2664,7 +2667,7 @@ public class CPPSemantics { if (!isUserDefined(op1type) && !isUserDefined(op2type)) return null; - lookupNonMember= true; + lookupNonMember= NonMemberMode.limited; } return findOverloadedOperator(exp, args, op1type, op.toCharArray(), lookupNonMember); @@ -2687,10 +2690,12 @@ public class CPPSemantics { char[] name = OverloadableOperator.COMMA.toCharArray(); IASTExpression[] args = new IASTExpression[] { dummy , second }; - return findOverloadedOperator(dummy, args, lookupType, name, true); + return findOverloadedOperator(dummy, args, lookupType, name, NonMemberMode.limited); } - private static ICPPFunction findOverloadedOperator(IASTExpression parent, IASTExpression[] args, IType methodLookupType, char[] operatorName, boolean lookupNonMember) { + enum NonMemberMode {none, limited, all} + private static ICPPFunction findOverloadedOperator(IASTExpression parent, IASTExpression[] args, IType methodLookupType, + char[] operatorName, NonMemberMode mode) { ICPPClassType callToObjectOfClassType= null; // Find a method @@ -2725,7 +2730,7 @@ public class CPPSemantics { // Find a function LookupData funcData = null; CPPASTName funcName = null; - if (lookupNonMember || callToObjectOfClassType != null) { + if (mode != NonMemberMode.none || callToObjectOfClassType != null) { funcName = new CPPASTName(operatorName); funcName.setParent(parent); funcName.setPropertyInParent(STRING_LOOKUP_PROPERTY); @@ -2734,13 +2739,53 @@ public class CPPSemantics { funcData.ignoreMembers = true; // (13.3.1.2.3) try { - if (lookupNonMember) { + if (mode != NonMemberMode.none) { IScope scope = CPPVisitor.getContainingScope(parent); if (scope == null) return null; lookup(funcData, scope); } - if (callToObjectOfClassType != null) { + } catch (DOMException e) { + return null; + } + + // 13.3.1.2.3 + // However, if no operand type has class type, only those non-member functions ... + if (mode == NonMemberMode.limited) { + IType type2= args.length < 2 ? null : getUltimateTypeUptoPointers(args[1].getExpressionType()); + if (funcData.foundItems != null && !(methodLookupType instanceof ICPPClassType) && !(type2 instanceof ICPPClassType)) { + IEnumeration enum1= null; + IEnumeration enum2= null; + if (methodLookupType instanceof IEnumeration) { + enum1= (IEnumeration) methodLookupType; + } + if (type2 instanceof IEnumeration) { + enum2= (IEnumeration) type2; + } + Object[] items= (Object[]) funcData.foundItems; + int j= 0; + for (Object object : items) { + if (object instanceof ICPPFunction) { + ICPPFunction func= (ICPPFunction) object; + try { + ICPPFunctionType ft = func.getType(); + IType[] pts= ft.getParameterTypes(); + if ((enum1 != null && pts.length > 0 && enum1.isSameType(getUltimateTypeUptoPointers(pts[0]))) || + (enum2 != null && pts.length > 1 && enum2.isSameType(getUltimateTypeUptoPointers(pts[1])))) { + items[j++]= object; + } + } catch (DOMException e) { + } + } + } + while(j < items.length) { + items[j++]= null; + } + } + } + + if (callToObjectOfClassType != null) { + try { // 13.3.1.1.2 call to object of class type ICPPMethod[] ops = SemanticUtil.getConversionOperators(callToObjectOfClassType); for (ICPPMethod op : ops) { @@ -2757,9 +2802,9 @@ public class CPPSemantics { } } } + } catch (DOMException e) { + return null; } - } catch (DOMException e) { - return null; } } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPTemplates.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPTemplates.java index 95c1f85d72c..f4972e71ab3 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPTemplates.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPTemplates.java @@ -672,7 +672,11 @@ public class CPPTemplates { final int length = tmplParams.length; ICPPTemplateArgument[] result = new ICPPTemplateArgument[length]; - if (!deduceTemplateParameterMap(template.getType().getReturnType(), conversionType, map)) { + IType a= SemanticUtil.getSimplifiedType(conversionType); + final boolean isReferenceType = a instanceof ICPPReferenceType; + final IType p= getArgumentTypeForDeduction(template.getType().getReturnType(), isReferenceType); + a= getParameterTypeForDeduction(a, isReferenceType); + if (!deduceTemplateParameterMap(p, a, map)) { return null; } @@ -1407,10 +1411,6 @@ public class CPPTemplates { } } - static protected void instantiateConversionTemplates(IFunction[] functions, IType conversionType, IASTName name) { - instantiateConversionTemplates(functions, conversionType); - } - static protected void instantiateConversionTemplates(IFunction[] functions, IType conversionType) { boolean checkedForDependentType= false; for (int i = 0; i < functions.length; i++) { @@ -1546,6 +1546,8 @@ public class CPPTemplates { /** * 14.8.2.1-2 If P is a cv-qualified type, the top level cv-qualifiers of P's type are ignored for type * deduction. If P is a reference type, the type referred to by P is used for Type deduction. + * + * Also 14.8.2.3-2 where the same logics is used in reverse. */ static private IType getParameterTypeForDeduction(IType pType, boolean isReferenceType) { if (isReferenceType) { @@ -1560,9 +1562,8 @@ public class CPPTemplates { * - If A is an array type, the pointer type produced by the array-to-pointer conversion is used instead * - If A is a function type, the pointer type produced by the function-to-pointer conversion is used instead * - If A is a cv-qualified type, the top level cv-qualifiers are ignored for type deduction - * @param type argument type - * @param parameterIsAReferenceType indicates whether template parameter is a reference type. - * @return + * + * Also 14.8.2.3-2 where the same logics is used in reverse. */ static private IType getArgumentTypeForDeduction(IType type, boolean parameterIsAReferenceType) { type = SemanticUtil.getSimplifiedType(type); 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 05260c97a47..d119045d592 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 @@ -25,6 +25,7 @@ import org.eclipse.cdt.core.dom.ast.IBasicType; import org.eclipse.cdt.core.dom.ast.IBinding; import org.eclipse.cdt.core.dom.ast.IEnumeration; import org.eclipse.cdt.core.dom.ast.IFunctionType; +import org.eclipse.cdt.core.dom.ast.IParameter; import org.eclipse.cdt.core.dom.ast.IPointerType; import org.eclipse.cdt.core.dom.ast.IProblemBinding; import org.eclipse.cdt.core.dom.ast.IQualifierType; @@ -34,7 +35,9 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPBase; import org.eclipse.cdt.core.dom.ast.cpp.ICPPBasicType; import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassType; import org.eclipse.cdt.core.dom.ast.cpp.ICPPConstructor; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPFunctionType; import org.eclipse.cdt.core.dom.ast.cpp.ICPPMethod; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPParameter; import org.eclipse.cdt.core.dom.ast.cpp.ICPPPointerToMemberType; import org.eclipse.cdt.core.dom.ast.cpp.ICPPReferenceType; import org.eclipse.cdt.core.dom.ast.cpp.ICPPSpecialization; @@ -58,7 +61,7 @@ public class Conversions { /** * Computes the cost of an implicit conversion sequence * [over.best.ics] 13.3.3.1 - * @param sourceExp the expression behind the source type + * @param sourceIsLValue whether the source type is an lvalue * @param source the source (argument) type * @param target the target (parameter) type * @param isImpliedObject @@ -66,7 +69,7 @@ public class Conversions { * @return the cost of converting from source to target * @throws DOMException */ - public static Cost checkImplicitConversionSequence(IASTExpression sourceExp, IType source, + public static Cost checkImplicitConversionSequence(boolean sourceIsLValue, IType source, IType target, UDCMode udc, boolean isImpliedObject) throws DOMException { if (isImpliedObject) { udc= UDCMode.noUDC; @@ -79,14 +82,15 @@ public class Conversions { // [8.5.3-5] initialization of a reference IType cv1T1= getNestedType(target, TDEF | REF); - boolean lvalue= sourceExp == null || !CPPVisitor.isRValue(sourceExp); - if (source instanceof ICPPReferenceType) + if (source instanceof ICPPReferenceType) { + sourceIsLValue= true; source= getNestedType(source, TDEF | REF); + } IType T2= getNestedType(source, TDEF | REF | CVQ | PTR_CVQ); // [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 (sourceIsLValue) { Cost cost= isReferenceCompatible(cv1T1, source, isImpliedObject); if (cost != null) { // [8.5.3-5] this is a direct reference binding @@ -135,7 +139,7 @@ public class Conversions { // [8.5.3-5] Direct binding failed - Otherwise boolean cv1isConst= getCVQualifier(cv1T1) == 1; if (cv1isConst) { - if (!lvalue && T2 instanceof ICPPClassType) { + if (!sourceIsLValue && T2 instanceof ICPPClassType) { Cost cost= isReferenceCompatible(cv1T1, source, isImpliedObject); if (cost != null) return cost; @@ -156,7 +160,7 @@ public class Conversions { // We must do a non-reference initialization if (!illformed) { - return nonReferenceConversion(source, cv1T1, udc, isImpliedObject); + return nonReferenceConversion(sourceIsLValue, source, cv1T1, udc, isImpliedObject); } } } @@ -164,31 +168,36 @@ public class Conversions { } // Non-reference binding - // [13.3.3.1-6] Subsume cv-qualifications - source= getNestedType(source, TDEF | REF | CVQ | PTR_CVQ); - target= getNestedType(target, TDEF | REF | CVQ | PTR_CVQ); + IType uqsource= getNestedType(source, TDEF | REF | CVQ); + IType uqtarget= getNestedType(target, TDEF | REF | CVQ); // [13.3.3.1-6] Derived to base conversion - if (source instanceof ICPPClassType && target instanceof ICPPClassType) { - int depth= calculateInheritanceDepth(CPPSemantics.MAX_INHERITANCE_DEPTH, source, target); + if (uqsource instanceof ICPPClassType && uqtarget instanceof ICPPClassType) { + int depth= calculateInheritanceDepth(CPPSemantics.MAX_INHERITANCE_DEPTH, uqsource, uqtarget); if (depth > -1) { if (depth == 0) { - return new Cost(source, target, Rank.IDENTITY); + return new Cost(uqsource, uqtarget, Rank.IDENTITY); } - Cost cost= new Cost(source, target, Rank.CONVERSION); + Cost cost= new Cost(uqsource, uqtarget, Rank.CONVERSION); cost.setInheritanceDistance(depth); return cost; } } - return nonReferenceConversion(source, target, udc, isImpliedObject); + + // [13.3.3.1-6] Subsume cv-qualifications + if (!(uqsource instanceof ICPPClassType) && !(uqtarget instanceof ICPPClassType)) { + source= uqsource; + target= uqtarget; + } + return nonReferenceConversion(sourceIsLValue, source, target, udc, isImpliedObject); } - private static Cost nonReferenceConversion(IType source, IType target, UDCMode udc, boolean isImpliedObject) throws DOMException { + private static Cost nonReferenceConversion(boolean sourceIsLValue, IType source, IType target, UDCMode udc, boolean isImpliedObject) throws DOMException { Cost cost= checkStandardConversionSequence(source, target, isImpliedObject); if (cost.getRank() != Rank.NO_MATCH || udc == UDCMode.noUDC) return cost; - Cost temp = checkUserDefinedConversionSequence(source, target, udc == UDCMode.deferUDC); + Cost temp = checkUserDefinedConversionSequence(sourceIsLValue, source, target, udc == UDCMode.deferUDC); if (temp != null) { cost = temp; } @@ -340,10 +349,7 @@ public class Conversions { * @return * @throws DOMException */ - static final Cost checkUserDefinedConversionSequence(IType source, IType target, boolean deferUDC) throws DOMException { - Cost constructorCost= null; - Cost operatorCost= null; - + static final Cost checkUserDefinedConversionSequence(boolean sourceIsLValue, IType source, IType target, boolean deferUDC) throws DOMException { IType s= getNestedType(source, TDEF | CVQ | REF); IType t= getNestedType(target, TDEF | CVQ | REF); @@ -352,69 +358,115 @@ public class Conversions { } if (deferUDC) { - Cost c= new Cost(s, t, Rank.USER_DEFINED_CONVERSION); + Cost c= new Cost(source, target, Rank.USER_DEFINED_CONVERSION); c.setDeferredUDC(true); return c; } - // Constructors + // 13.3.1.4 Copy initialization of class by user-defined conversion if (t instanceof ICPPClassType) { + Cost cost1= null; + Cost cost2= null; ICPPConstructor[] ctors= ((ICPPClassType) t).getConstructors(); - // Select converting constructors - int j= 0; - ICPPConstructor[] convertingCtors= new ICPPConstructor[ctors.length]; + CPPTemplates.instantiateFunctionTemplates(ctors, new IType[]{source}, null); + for (ICPPConstructor ctor : ctors) { - if (!(ctor instanceof IProblemBinding) && !ctor.isExplicit()) - convertingCtors[j++]= ctor; - } - if (j > 0) { - LookupData data= new LookupData(); - data.setFunctionArgumentTypes(new IType[] { source }); - IBinding binding = CPPSemantics.resolveFunction(data, convertingCtors, false); - if (binding instanceof ICPPConstructor && !(binding instanceof IProblemBinding)) { - constructorCost = checkStandardConversionSequence(t, target, false); - if (constructorCost.getRank() == Rank.NO_MATCH) { - constructorCost= null; + if (ctor != null && !(ctor instanceof IProblemBinding) && !ctor.isExplicit()) { + final ICPPFunctionType ft = ctor.getType(); + final IType[] ptypes = ft.getParameterTypes(); + Cost c1; + if (ptypes.length == 0) { + if (ctor.takesVarArgs()) { + c1= new Cost(source, null, Rank.ELLIPSIS_CONVERSION); + } else { + continue; + } } else { - constructorCost.setUserDefinedConversion((ICPPConstructor) binding); + if (ptypes.length > 1) { + IParameter[] pars = ctor.getParameters(); + if (pars.length < 2 || !((ICPPParameter) pars[1]).hasDefaultValue()) + continue; + } + c1= checkImplicitConversionSequence(sourceIsLValue, source, ptypes[0], UDCMode.noUDC, false); } - } - } - } - - // Conversion operators - boolean ambiguousConversionOperator= false; - if (s instanceof ICPPClassType) { - ICPPMethod[] ops = SemanticUtil.getConversionOperators((ICPPClassType) s); - CPPTemplates.instantiateConversionTemplates(ops, target); - for (final ICPPMethod op : ops) { - if (op != null && !(op instanceof IProblemBinding)) { - Cost cost= checkStandardConversionSequence(op.getType().getReturnType(), target, false); - if (cost.getRank() != Rank.NO_MATCH) { - int cmp= cost.compareTo(operatorCost); - if (cmp <= 0) { - cost.setUserDefinedConversion(op); - operatorCost= cost; - ambiguousConversionOperator= cmp == 0; + int cmp= c1.compareTo(cost1); + if (cmp <= 0) { + cost1= c1; + cost2= new Cost(t, t, Rank.IDENTITY); + cost2.setUserDefinedConversion(ctor); + if (cmp == 0) { + cost2.setAmbiguousUDC(true); } } } } + if (s instanceof ICPPClassType) { + ICPPMethod[] ops = SemanticUtil.getConversionOperators((ICPPClassType) s); + CPPTemplates.instantiateConversionTemplates(ops, target); + for (final ICPPMethod op : ops) { + if (op != null && !(op instanceof IProblemBinding)) { + final IType returnType = op.getType().getReturnType(); + final IType uqReturnType= getNestedType(returnType, REF | TDEF | CVQ); + final int dist = calculateInheritanceDepth(CPPSemantics.MAX_INHERITANCE_DEPTH, uqReturnType, t); + if (dist >= 0) { + final ICPPFunctionType ft = op.getType(); + IType implicitType= CPPSemantics.getImplicitType(op, ft.isConst(), ft.isVolatile()); + Cost c1= checkImplicitConversionSequence(sourceIsLValue, source, implicitType, UDCMode.noUDC, false); + int cmp= c1.compareTo(cost1); + if (cmp <= 0) { + cost1= c1; + cost2= new Cost(t, t, Rank.IDENTITY); + if (dist > 0) { + cost2.setInheritanceDistance(dist); + cost2.setRank(Rank.CONVERSION); + } + cost2.setUserDefinedConversion(op); + if (cmp == 0) { + cost2.setAmbiguousUDC(true); + } + } + } + } + } + } + if (cost1 == null || cost1.getRank() == Rank.NO_MATCH) + return null; + + return cost2; } - - if (constructorCost != null) { - if (operatorCost != null && !ambiguousConversionOperator) { - // If both are valid, then the conversion is ambiguous - constructorCost.setAmbiguousUDC(true); - } - return constructorCost; - } - if (operatorCost != null) { - operatorCost.setAmbiguousUDC(ambiguousConversionOperator); - return operatorCost; + // 13.3.1.5 Initialization by conversion function + if (s instanceof ICPPClassType) { + ICPPMethod[] ops = SemanticUtil.getConversionOperators((ICPPClassType) s); + CPPTemplates.instantiateConversionTemplates(ops, target); + Cost cost1= null; + Cost cost2= null; + for (final ICPPMethod op : ops) { + if (op != null && !(op instanceof IProblemBinding)) { + final IType returnType = op.getType().getReturnType(); + IType uqReturnType= getNestedType(returnType, TDEF | CVQ | PTR_CVQ); + Cost c2= checkImplicitConversionSequence(false, uqReturnType, target, UDCMode.noUDC, false); + if (c2.getRank() != Rank.NO_MATCH) { + ICPPFunctionType ftype = op.getType(); + IType implicitType= CPPSemantics.getImplicitType(op, ftype.isConst(), ftype.isVolatile()); + Cost c1= checkImplicitConversionSequence(sourceIsLValue, source, implicitType, UDCMode.noUDC, false); + int cmp= c1.compareTo(cost1); + if (cmp <= 0) { + cost1= c1; + cost2= c2; + cost2.setUserDefinedConversion(op); + if (cmp == 0) { + cost2.setAmbiguousUDC(true); + } + } + } + } + } + if (cost1 == null || cost1.getRank() == Rank.NO_MATCH) + return null; + + return cost2; } - return null; } @@ -544,6 +596,7 @@ public class Conversions { // This should actually be done in 'checkImplicitConversionSequence', see 13.3.3.1-6 and 8.5.14 // 8.5.14 cv-qualifiers can be ignored for non-class types + // mstodo IType unqualifiedTarget= getNestedType(target, CVQ | PTR_CVQ | TDEF | REF); if (!(unqualifiedTarget instanceof ICPPClassType)) { IType unqualifiedSource= getNestedType(source, CVQ | PTR_CVQ | TDEF | REF); diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/FunctionCost.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/FunctionCost.java index 3543424cbc0..f789cd476ed 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/FunctionCost.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/FunctionCost.java @@ -10,6 +10,8 @@ *******************************************************************************/ package org.eclipse.cdt.internal.core.dom.parser.cpp.semantics; +import java.util.BitSet; + import org.eclipse.cdt.core.dom.ast.DOMException; import org.eclipse.cdt.core.dom.ast.IBinding; import org.eclipse.cdt.core.dom.ast.IFunction; @@ -23,10 +25,12 @@ import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.Cost.Rank; class FunctionCost { private final IFunction fFunction; private final Cost[] fCosts; + private final BitSet fSourceIsLValue; public FunctionCost(IFunction fn, int paramCount) { fFunction= fn; fCosts= new Cost[paramCount]; + fSourceIsLValue= new BitSet(paramCount); } public int getLength() { @@ -37,8 +41,9 @@ class FunctionCost { return fCosts[idx]; } - public void setCost(int idx, Cost cost) { + public void setCost(int idx, Cost cost, boolean sourceIsLValue) { fCosts[idx]= cost; + fSourceIsLValue.set(idx, sourceIsLValue); } public IFunction getFunction() { @@ -65,7 +70,7 @@ class FunctionCost { for (int i = 0; i < fCosts.length; i++) { Cost cost = fCosts[i]; if (cost.isDeferredUDC()) { - Cost udcCost= Conversions.checkUserDefinedConversionSequence(cost.source, cost.target, false); + Cost udcCost= Conversions.checkUserDefinedConversionSequence(fSourceIsLValue.get(i), cost.source, cost.target, false); if (udcCost == null) { return false; }