1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-04-29 19:45:01 +02:00

User-defined conversions, bug 222444.

This commit is contained in:
Markus Schorn 2009-10-15 15:28:25 +00:00
parent 6744e78d21
commit 36181bd862
6 changed files with 317 additions and 104 deletions

View file

@ -7468,5 +7468,94 @@ public class AST2CPPTests extends AST2BaseTest {
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);
}
}

View file

@ -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);
}

View file

@ -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;
}
}

View file

@ -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);

View file

@ -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];
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;
} else {
constructorCost.setUserDefinedConversion((ICPPConstructor) binding);
}
}
}
}
CPPTemplates.instantiateFunctionTemplates(ctors, new IType[]{source}, null);
// 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;
for (ICPPConstructor ctor : ctors) {
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 {
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);
}
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 (constructorCost != null) {
if (operatorCost != null && !ambiguousConversionOperator) {
// If both are valid, then the conversion is ambiguous
constructorCost.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);
}
}
}
}
}
}
return constructorCost;
if (cost1 == null || cost1.getRank() == Rank.NO_MATCH)
return null;
return cost2;
}
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);

View file

@ -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;
}