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:
parent
6744e78d21
commit
36181bd862
6 changed files with 317 additions and 104 deletions
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue