1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-06-08 18:26:01 +02:00

Bug 302412: List initialization with elements of the initializer list.

This commit is contained in:
Markus Schorn 2010-03-12 11:53:43 +00:00
parent bd8092d830
commit ce38a4facd
8 changed files with 274 additions and 57 deletions

View file

@ -8140,5 +8140,78 @@ public class AST2CPPTests extends AST2BaseTest {
bh.assertProblem("f( {1.0} )", 1); bh.assertProblem("f( {1.0} )", 1);
bh.assertNonProblem("g({ \"foo\", \"bar\" })", 1); bh.assertNonProblem("g({ \"foo\", \"bar\" })", 1);
} }
// namespace std {
// template<typename T> class initializer_list;
// }
// struct str {
// str(const char*) {
// }
// };
// struct A {
// A(std::initializer_list<int>);
// };
// struct B {
// B(int, double);
// };
// struct C {
// C(str);
// };
// struct D {
// D(A, C);
// };
// struct X {
// X();
// X(X&);
// };
// void e(A);
// void f(A);
// void f(B);
// void g(B);
// void h(C);
// void i(D);
// void x(const X);
//
// void test() {
// e( { 'a', 'b' }); // OK: f(A(std::initializer_list<int>)) user-defined conversion
// g( { 'a', 'b' }); // OK: g(B(int,double)) user-defined conversion
// g( { 1.0, 1.0 }); // error: narrowing
// f( { 'a', 'b' }); // error: ambiguous f(A) or f(B)
// h( { "foo" }); // OK: h(C(std::string("foo")))
// i( { { 1, 2 }, { "bar" } }); // OK: i(D(A(std::initializer_list<int>{1,2}),C(std::string("bar"))))
// X x1;
// x({x1}); // no matching constructor
// }
public void testListInitialization_302412c() throws Exception {
String code= getAboveComment();
BindingAssertionHelper bh= new BindingAssertionHelper(code, true);
bh.assertNonProblem("e( { 'a', 'b' })", 1);
bh.assertNonProblem("g( { 'a', 'b' })", 1);
bh.assertProblem("g( { 1.0, 1.0 })", 1);
bh.assertProblem("f( { 'a', 'b' })", 1);
bh.assertNonProblem("h( {", 1);
bh.assertNonProblem("i( { { 1, 2 }, {", 1);
bh.assertProblem("x({x1})", 1);
}
// namespace std {
// template<typename T> class initializer_list;
// }
// struct A {
// int m1;
// double m2;
// };
// void f(A);
// void test() {
// f( {'a', 'b'} ); // OK: f(A(int,double)) user-defined conversion
// f( {1.0} ); // narrowing not detected by cdt.
// }
public void testListInitialization_302412d() throws Exception {
String code= getAboveComment();
BindingAssertionHelper bh= new BindingAssertionHelper(code, true);
bh.assertNonProblem("f( {'a', 'b'} )", 1);
// not detected by CDT
// bh.assertProblem("f( {1.0} )", 1);
}
} }

View file

@ -15,6 +15,7 @@ import org.eclipse.cdt.core.dom.ast.IBasicType;
import org.eclipse.cdt.core.dom.ast.IEnumeration; import org.eclipse.cdt.core.dom.ast.IEnumeration;
import org.eclipse.cdt.core.dom.ast.IType; import org.eclipse.cdt.core.dom.ast.IType;
import org.eclipse.cdt.core.dom.ast.IBasicType.Kind; import org.eclipse.cdt.core.dom.ast.IBasicType.Kind;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPBasicType;
/** /**
* Arithmetic conversions as required to compute the type of unary or binary expressions. * Arithmetic conversions as required to compute the type of unary or binary expressions.
@ -278,4 +279,43 @@ public abstract class ArithmeticConversion {
return IBasicType.IS_UNSIGNED | IBasicType.IS_LONG; return IBasicType.IS_UNSIGNED | IBasicType.IS_LONG;
} }
} }
public static boolean fitsIntoType(ICPPBasicType basicTarget, long n) {
final Kind kind = basicTarget.getKind();
switch (kind) {
case eInt:
if (!basicTarget.isUnsigned()) {
if (basicTarget.isShort()) {
return Short.MIN_VALUE <= n && n <= Short.MAX_VALUE;
}
// Can't represent long longs with java longs.
if (basicTarget.isLong() || basicTarget.isLongLong()) {
return true;
}
return Integer.MIN_VALUE <= n && n <= Integer.MAX_VALUE;
}
if (n < 0)
return false;
if (basicTarget.isShort()) {
return n < (Short.MAX_VALUE + 1L)*2;
}
// Can't represent long longs with java longs.
if (basicTarget.isLong() || basicTarget.isLongLong()) {
return true;
}
return n < (Integer.MAX_VALUE + 1L)*2;
case eFloat:
float f= n;
return (long)f == n;
case eDouble:
double d= n;
return (long)d == n;
default:
return false;
}
}
} }

View file

@ -2296,7 +2296,7 @@ public class CPPSemantics {
cost = new Cost(thisType, implicitType, Rank.IDENTITY); cost = new Cost(thisType, implicitType, Rank.IDENTITY);
} else { } else {
cost = Conversions.checkImplicitConversionSequence(implicitType, thisType, sourceIsLValue, UDCMode.noUDC, true); cost = Conversions.checkImplicitConversionSequence(implicitType, thisType, sourceIsLValue, UDCMode.noUDC, true);
if (cost.getRank() == Rank.NO_MATCH) { if (!cost.converts()) {
if (CPPTemplates.isDependentType(implicitType) || CPPTemplates.isDependentType(thisType)) { if (CPPTemplates.isDependentType(implicitType) || CPPTemplates.isDependentType(thisType)) {
IType s= getNestedType(thisType, TDEF|REF|CVTYPE); IType s= getNestedType(thisType, TDEF|REF|CVTYPE);
IType t= getNestedType(implicitType, TDEF|REF|CVTYPE); IType t= getNestedType(implicitType, TDEF|REF|CVTYPE);
@ -2307,7 +2307,7 @@ public class CPPSemantics {
} }
} }
} }
if (cost.getRank() == Rank.NO_MATCH) if (!cost.converts())
return null; return null;
result.setCost(k++, cost, sourceIsLValue); result.setCost(k++, cost, sourceIsLValue);
@ -2338,8 +2338,11 @@ public class CPPSemantics {
if (CPPTemplates.isDependentType(paramType)) if (CPPTemplates.isDependentType(paramType))
return CONTAINS_DEPENDENT_TYPES; return CONTAINS_DEPENDENT_TYPES;
cost = Conversions.checkImplicitConversionSequence(paramType, argType, sourceIsLValue, udc, false); cost = Conversions.checkImplicitConversionSequence(paramType, argType, sourceIsLValue, udc, false);
if (data.fNoNarrowing && cost.isNarrowingConversion()) {
cost= Cost.NO_CONVERSION;
} }
if (cost.getRank() == Rank.NO_MATCH) }
if (!cost.converts())
return null; return null;
result.setCost(k++, cost, sourceIsLValue); result.setCost(k++, cost, sourceIsLValue);

View file

@ -140,7 +140,6 @@ import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPUnknownClassInstance;
import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPUnknownClassType; import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPUnknownClassType;
import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPUnknownType; import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPUnknownType;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.Conversions.UDCMode; import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.Conversions.UDCMode;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.Cost.Rank;
/** /**
* Collection of static methods to perform template instantiation, member specialization and * Collection of static methods to perform template instantiation, member specialization and
@ -1966,7 +1965,7 @@ public class CPPTemplates {
paramType = new CPPPointerType(((IArrayType) paramType).getType()); paramType = new CPPPointerType(((IArrayType) paramType).getType());
} }
Cost cost = Conversions.checkImplicitConversionSequence(paramType, arg, true, UDCMode.noUDC, false); Cost cost = Conversions.checkImplicitConversionSequence(paramType, arg, true, UDCMode.noUDC, false);
return cost != null && cost.getRank() != Rank.NO_MATCH; return cost != null && cost.converts();
} }
static boolean argsAreTrivial(ICPPTemplateParameter[] pars, ICPPTemplateArgument[] args) { static boolean argsAreTrivial(ICPPTemplateParameter[] pars, ICPPTemplateArgument[] args) {

View file

@ -21,7 +21,9 @@ import java.util.BitSet;
import org.eclipse.cdt.core.dom.ast.DOMException; import org.eclipse.cdt.core.dom.ast.DOMException;
import org.eclipse.cdt.core.dom.ast.IASTExpression; import org.eclipse.cdt.core.dom.ast.IASTExpression;
import org.eclipse.cdt.core.dom.ast.IASTInitializerClause;
import org.eclipse.cdt.core.dom.ast.IASTLiteralExpression; import org.eclipse.cdt.core.dom.ast.IASTLiteralExpression;
import org.eclipse.cdt.core.dom.ast.IASTName;
import org.eclipse.cdt.core.dom.ast.IArrayType; import org.eclipse.cdt.core.dom.ast.IArrayType;
import org.eclipse.cdt.core.dom.ast.IBasicType; import org.eclipse.cdt.core.dom.ast.IBasicType;
import org.eclipse.cdt.core.dom.ast.IBinding; import org.eclipse.cdt.core.dom.ast.IBinding;
@ -33,6 +35,7 @@ import org.eclipse.cdt.core.dom.ast.IQualifierType;
import org.eclipse.cdt.core.dom.ast.IType; import org.eclipse.cdt.core.dom.ast.IType;
import org.eclipse.cdt.core.dom.ast.IValue; import org.eclipse.cdt.core.dom.ast.IValue;
import org.eclipse.cdt.core.dom.ast.IBasicType.Kind; import org.eclipse.cdt.core.dom.ast.IBasicType.Kind;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTInitializerList;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPBasicType; import org.eclipse.cdt.core.dom.ast.cpp.ICPPBasicType;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassSpecialization; import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassSpecialization;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassType; import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassType;
@ -47,6 +50,7 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateInstance;
import org.eclipse.cdt.core.parser.util.CharArrayUtils; import org.eclipse.cdt.core.parser.util.CharArrayUtils;
import org.eclipse.cdt.internal.core.dom.parser.ArithmeticConversion; import org.eclipse.cdt.internal.core.dom.parser.ArithmeticConversion;
import org.eclipse.cdt.internal.core.dom.parser.Value; import org.eclipse.cdt.internal.core.dom.parser.Value;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTName;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPBasicType; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPBasicType;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPPointerToMemberType; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPPointerToMemberType;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPPointerType; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPPointerType;
@ -145,7 +149,7 @@ public class Conversions {
ok= !exprIsLValue; ok= !exprIsLValue;
} }
if (!ok) { if (!ok) {
return new Cost(exprType, cv1T1, Rank.NO_MATCH); return Cost.NO_CONVERSION;
} }
// If T1 and T2 are class types and ... // If T1 and T2 are class types and ...
@ -204,7 +208,7 @@ public class Conversions {
return cost; return cost;
} }
} }
return new Cost(exprType, cv1T1, Rank.NO_MATCH); return Cost.NO_CONVERSION;
} }
// Non-reference binding // Non-reference binding
@ -274,14 +278,10 @@ public class Conversions {
// [13.3.3.1-6] Subsume cv-qualifications // [13.3.3.1-6] Subsume cv-qualifications
IType uqSource= SemanticUtil.getNestedType(source, TDEF | ALLCVQ); IType uqSource= SemanticUtil.getNestedType(source, TDEF | ALLCVQ);
Cost cost= checkStandardConversionSequence(uqSource, sourceIsLValue, target, isImpliedObject); Cost cost= checkStandardConversionSequence(uqSource, sourceIsLValue, target, isImpliedObject);
if (cost.getRank() != Rank.NO_MATCH || udc == UDCMode.noUDC) if (cost.converts() || udc == UDCMode.noUDC)
return cost; return cost;
Cost temp = checkUserDefinedConversionSequence(sourceIsLValue, source, target, udc == UDCMode.deferUDC); return checkUserDefinedConversionSequence(sourceIsLValue, source, target, udc == UDCMode.deferUDC);
if (temp != null) {
cost = temp;
}
return cost;
} }
/** /**
@ -296,7 +296,7 @@ public class Conversions {
for (int i = 0; i < exprTypes.length; i++) { for (int i = 0; i < exprTypes.length; i++) {
IType exprType = exprTypes[i]; IType exprType = exprTypes[i];
Cost cost= checkImplicitConversionSequence(listType, exprType, isLValue.get(i), UDCMode.allowUDC, false); Cost cost= checkImplicitConversionSequence(listType, exprType, isLValue.get(i), UDCMode.allowUDC, false);
if (cost.getRank() == Rank.NO_MATCH) if (!cost.converts())
return cost; return cost;
if (cost.isNarrowingConversion()) { if (cost.isNarrowingConversion()) {
cost.setRank(Rank.NO_MATCH); cost.setRank(Rank.NO_MATCH);
@ -312,17 +312,17 @@ public class Conversions {
IType noCVTarget= getNestedType(target, CVTYPE | TDEF); IType noCVTarget= getNestedType(target, CVTYPE | TDEF);
if (noCVTarget instanceof ICPPClassType) { if (noCVTarget instanceof ICPPClassType) {
if (udc == UDCMode.noUDC) if (udc == UDCMode.noUDC)
return new Cost(arg, target, Rank.NO_MATCH); return Cost.NO_CONVERSION;
ICPPClassType classTarget= (ICPPClassType) noCVTarget; ICPPClassType classTarget= (ICPPClassType) noCVTarget;
if (ClassTypeHelper.isAggregateClass(classTarget)) { if (ClassTypeHelper.isAggregateClass(classTarget)) {
return new Cost(arg, target, Rank.USER_DEFINED_CONVERSION); Cost cost= new Cost(arg, target, Rank.IDENTITY);
} cost.setUserDefinedConversion(null);
Cost cost= checkUserDefinedConversionSequence(false, arg, target, udc == UDCMode.deferUDC);
if (cost != null)
return cost; return cost;
} }
return new Cost(arg, target, Rank.NO_MATCH); return checkUserDefinedConversionSequence(false, arg, target, udc == UDCMode.deferUDC);
}
return Cost.NO_CONVERSION;
} }
private static IType getInitListType(IType target) throws DOMException { private static IType getInitListType(IType target) throws DOMException {
@ -492,18 +492,13 @@ public class Conversions {
/** /**
* [13.3.3.1.2] User-defined conversions * [13.3.3.1.2] User-defined conversions
* @param source
* @param target
* @return
* @throws DOMException
*/ */
static final Cost checkUserDefinedConversionSequence(boolean sourceIsLValue, IType source, IType target, boolean deferUDC) throws DOMException { static final Cost checkUserDefinedConversionSequence(boolean sourceIsLValue, IType source, IType target, boolean deferUDC) throws DOMException {
// mstodo don't return null
IType s= getNestedType(source, TDEF | CVTYPE | REF); IType s= getNestedType(source, TDEF | CVTYPE | REF);
IType t= getNestedType(target, TDEF | CVTYPE | REF); IType t= getNestedType(target, TDEF | CVTYPE | REF);
if (!(s instanceof ICPPClassType || t instanceof ICPPClassType)) { if (!(s instanceof ICPPClassType || t instanceof ICPPClassType)) {
return null; return Cost.NO_CONVERSION;
} }
if (deferUDC) { if (deferUDC) {
@ -525,26 +520,25 @@ public class Conversions {
// 13.3.1.5 Initialization by conversion function // 13.3.1.5 Initialization by conversion function
return initializationByConversion(source, (ICPPClassType) s, target); return initializationByConversion(source, (ICPPClassType) s, target);
} }
return null; return Cost.NO_CONVERSION;
} }
private static Cost listInitializationOfClass(InitializerListType s, ICPPClassType t, boolean isDirect) throws DOMException { private static Cost listInitializationOfClass(InitializerListType arg, ICPPClassType t, boolean isDirect) throws DOMException {
// If T has an initializer-list constructor // If T has an initializer-list constructor
ICPPConstructor usedCtor= null; ICPPConstructor usedCtor= null;
Cost bestCost= null; Cost bestCost= null;
ICPPConstructor[] ctors= t.getConstructors(); boolean hasInitListConstructor= false;
final ICPPConstructor[] constructors = t.getConstructors();
ICPPConstructor[] ctors= constructors;
for (ICPPConstructor ctor : ctors) { for (ICPPConstructor ctor : ctors) {
if (ctor.getRequiredArgumentCount() <= 1) { if (ctor.getRequiredArgumentCount() <= 1) {
IType[] parTypes= ctor.getType().getParameterTypes(); IType[] parTypes= ctor.getType().getParameterTypes();
if (parTypes.length > 0) { if (parTypes.length > 0) {
final IType target = parTypes[0]; final IType target = parTypes[0];
if (getInitListType(target) != null) { if (getInitListType(target) != null) {
Cost cost= listInitializationSequence(s, target, UDCMode.noUDC); hasInitListConstructor= true;
if (cost.getRank() == Rank.NO_MATCH) { Cost cost= listInitializationSequence(arg, target, UDCMode.noUDC);
if (bestCost == null) { if (cost.converts()) {
bestCost= cost;
}
} else {
int cmp= cost.compareTo(bestCost); int cmp= cost.compareTo(bestCost);
if (bestCost == null || cmp < 0) { if (bestCost == null || cmp < 0) {
usedCtor= ctor; usedCtor= ctor;
@ -558,7 +552,10 @@ public class Conversions {
} }
} }
} }
if (bestCost != null) { if (hasInitListConstructor) {
if (bestCost == null)
return Cost.NO_CONVERSION;
if (!bestCost.isAmbiguousUDC() && !isDirect) { if (!bestCost.isAmbiguousUDC() && !isDirect) {
if (usedCtor != null && usedCtor.isExplicit()) { if (usedCtor != null && usedCtor.isExplicit()) {
bestCost.setRank(Rank.NO_MATCH); bestCost.setRank(Rank.NO_MATCH);
@ -567,9 +564,47 @@ public class Conversions {
return bestCost; return bestCost;
} }
// mstodo expanding the list for selecting the ctor. // No initializer-list constructor
return new Cost(s, t, Rank.NO_MATCH); final ICPPASTInitializerList initializerList = arg.getInitializerList();
LookupData data= new LookupData();
IASTName name = new CPPASTName(t.getNameCharArray());
name.setParent(initializerList);
name.setPropertyInParent(CPPSemantics.STRING_LOOKUP_PROPERTY);
final IASTInitializerClause[] expandedArgs = initializerList.getClauses();
data.setFunctionArguments(expandedArgs);
data.fNoNarrowing= true;
// 13.3.3.1.4
ICPPConstructor[] filteredConstructors = constructors;
if (expandedArgs.length == 1) {
filteredConstructors= new ICPPConstructor[constructors.length];
int j=0;
for (ICPPConstructor ctor : constructors) {
if (ctor.getRequiredArgumentCount() < 2) {
IType[] ptypes= ctor.getType().getParameterTypes();
if (ptypes.length > 0) {
IType ptype= getNestedType(ptypes[0], TDEF | REF | CVTYPE);
if (!t.isSameType(ptype)) {
filteredConstructors[j++]= ctor;
}
}
}
}
}
final IBinding result= CPPSemantics.resolveFunction(data, filteredConstructors, true);
final Cost c;
if (result instanceof ICPPMethod) {
c= new Cost(arg, t, Rank.IDENTITY);
c.setUserDefinedConversion((ICPPMethod) result);
} else if (result instanceof IProblemBinding
&& ((IProblemBinding) result).getID() == IProblemBinding.SEMANTIC_AMBIGUOUS_LOOKUP) {
c = new Cost(arg, t, Rank.USER_DEFINED_CONVERSION);
c.setAmbiguousUDC(true);
} else {
c= Cost.NO_CONVERSION;
}
return c;
} }
/** /**
@ -646,8 +681,8 @@ public class Conversions {
} }
} }
} }
if (cost1 == null || cost1.getCost(0).getRank() == Rank.NO_MATCH) if (cost1 == null || !cost1.getCost(0).converts())
return null; return Cost.NO_CONVERSION;
return cost2; return cost2;
} }
@ -667,7 +702,7 @@ public class Conversions {
boolean isLValue = uqReturnType instanceof ICPPReferenceType boolean isLValue = uqReturnType instanceof ICPPReferenceType
&& !((ICPPReferenceType) uqReturnType).isRValueReference(); && !((ICPPReferenceType) uqReturnType).isRValueReference();
Cost c2= checkImplicitConversionSequence(target, uqReturnType, isLValue, UDCMode.noUDC, false); Cost c2= checkImplicitConversionSequence(target, uqReturnType, isLValue, UDCMode.noUDC, false);
if (c2.getRank() != Rank.NO_MATCH) { if (c2.converts()) {
ICPPFunctionType ftype = op.getType(); ICPPFunctionType ftype = op.getType();
IType implicitType= CPPSemantics.getImplicitType(op, ftype.isConst(), ftype.isVolatile()); IType implicitType= CPPSemantics.getImplicitType(op, ftype.isConst(), ftype.isVolatile());
final Cost udcCost = isReferenceCompatible(getNestedType(implicitType, TDEF | REF), source, true); final Cost udcCost = isReferenceCompatible(getNestedType(implicitType, TDEF | REF), source, true);
@ -686,8 +721,8 @@ public class Conversions {
} }
} }
} }
if (cost1 == null || cost1.getCost(0).getRank() == Rank.NO_MATCH) if (cost1 == null || !cost1.getCost(0).converts())
return null; return Cost.NO_CONVERSION;
return cost2; return cost2;
} }

View file

@ -13,16 +13,23 @@
*******************************************************************************/ *******************************************************************************/
package org.eclipse.cdt.internal.core.dom.parser.cpp.semantics; package org.eclipse.cdt.internal.core.dom.parser.cpp.semantics;
import org.eclipse.cdt.core.dom.ast.IASTExpression;
import org.eclipse.cdt.core.dom.ast.IASTLiteralExpression;
import org.eclipse.cdt.core.dom.ast.IType; import org.eclipse.cdt.core.dom.ast.IType;
import org.eclipse.cdt.core.dom.ast.IBasicType.Kind;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPBasicType;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPFunction; import org.eclipse.cdt.core.dom.ast.cpp.ICPPFunction;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPMethod; import org.eclipse.cdt.core.dom.ast.cpp.ICPPMethod;
import org.eclipse.cdt.internal.core.dom.parser.ArithmeticConversion;
import org.eclipse.cdt.internal.core.dom.parser.Value;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPBasicType;
/** /**
* The cost of an implicit conversion sequence. * The cost of an implicit conversion sequence.
* *
* See [over.best.ics] 13.3.3.1. * See [over.best.ics] 13.3.3.1.
*/ */
final class Cost { class Cost {
enum Rank { enum Rank {
IDENTITY, PROMOTION, CONVERSION, CONVERSION_PTR_BOOL, IDENTITY, PROMOTION, CONVERSION, CONVERSION_PTR_BOOL,
USER_DEFINED_CONVERSION, ELLIPSIS_CONVERSION, NO_MATCH USER_DEFINED_CONVERSION, ELLIPSIS_CONVERSION, NO_MATCH
@ -31,6 +38,41 @@ final class Cost {
RVALUE_REF_BINDS_RVALUE, LVALUE_REF, OTHER RVALUE_REF_BINDS_RVALUE, LVALUE_REF, OTHER
} }
public static final Cost NO_CONVERSION = new Cost(null, null, Rank.NO_MATCH) {
@Override
public void setRank(Rank rank) {
assert false;
}
@Override
public void setReferenceBinding(ReferenceBinding binding) {
assert false;
}
@Override
public void setAmbiguousUDC(boolean val) {
assert false;
}
@Override
public void setDeferredUDC(boolean val) {
assert false;
}
@Override
public void setInheritanceDistance(int inheritanceDistance) {
assert false;
}
@Override
public void setQualificationAdjustment(int adjustment) {
assert false;
}
@Override
public void setUserDefinedConversion(ICPPMethod conv) {
assert false;
}
@Override
public void setCouldNarrow() {
assert false;
}
};
IType source; IType source;
IType target; IType target;
@ -52,10 +94,14 @@ final class Cost {
fReferenceBinding= ReferenceBinding.OTHER; fReferenceBinding= ReferenceBinding.OTHER;
} }
public Rank getRank() { public final Rank getRank() {
return fRank; return fRank;
} }
public final boolean converts() {
return fRank != Rank.NO_MATCH;
}
public void setRank(Rank rank) { public void setRank(Rank rank) {
fRank= rank; fRank= rank;
} }
@ -99,10 +145,9 @@ final class Cost {
*/ */
public void setUserDefinedConversion(ICPPMethod conv) { public void setUserDefinedConversion(ICPPMethod conv) {
fUserDefinedConversion= conv; fUserDefinedConversion= conv;
if (conv != null) {
fSecondStandardConversionRank= fRank; fSecondStandardConversionRank= fRank;
fRank= Rank.USER_DEFINED_CONVERSION; fRank= Rank.USER_DEFINED_CONVERSION;
} fCouldNarrow= false;
} }
/** /**
@ -189,7 +234,26 @@ final class Cost {
} }
public boolean isNarrowingConversion() { public boolean isNarrowingConversion() {
return fCouldNarrow; if (fCouldNarrow) {
if (source instanceof CPPBasicType && target instanceof ICPPBasicType) {
ICPPBasicType basicTarget= (ICPPBasicType) target;
final Kind targetKind = basicTarget.getKind();
if (targetKind != Kind.eInt && targetKind != Kind.eFloat && targetKind != Kind.eDouble) {
return true;
}
IASTExpression val = ((CPPBasicType) source).getCreatedFromExpression();
if (val instanceof IASTLiteralExpression) {
// mstodo extend to constant expressions
Long l= Value.create(val, Value.MAX_RECURSION_DEPTH).numericalValue();
if (l != null) {
long n= l.longValue();
return !ArithmeticConversion.fitsIntoType(basicTarget, n);
}
}
}
return true;
}
return false;
} }
public void setCouldNarrow() { public void setCouldNarrow() {

View file

@ -17,7 +17,6 @@ import org.eclipse.cdt.core.dom.ast.IBinding;
import org.eclipse.cdt.core.dom.ast.IFunction; import org.eclipse.cdt.core.dom.ast.IFunction;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPFunctionTemplate; import org.eclipse.cdt.core.dom.ast.cpp.ICPPFunctionTemplate;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPSpecialization; import org.eclipse.cdt.core.dom.ast.cpp.ICPPSpecialization;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.Cost.Rank;
/** /**
* Cost for the entire function call * Cost for the entire function call
@ -66,6 +65,8 @@ class FunctionCost {
public boolean hasDeferredUDC() { public boolean hasDeferredUDC() {
for (Cost cost : fCosts) { for (Cost cost : fCosts) {
if (!cost.converts())
return false;
if (cost.isDeferredUDC()) if (cost.isDeferredUDC())
return true; return true;
} }
@ -77,10 +78,10 @@ class FunctionCost {
Cost cost = fCosts[i]; Cost cost = fCosts[i];
if (cost.isDeferredUDC()) { if (cost.isDeferredUDC()) {
Cost udcCost= Conversions.checkUserDefinedConversionSequence(fSourceIsLValue.get(i), cost.source, cost.target, false); Cost udcCost= Conversions.checkUserDefinedConversionSequence(fSourceIsLValue.get(i), cost.source, cost.target, false);
if (udcCost == null || udcCost.getRank() == Rank.NO_MATCH) { fCosts[i]= udcCost;
if (!udcCost.converts()) {
return false; return false;
} }
fCosts[i]= udcCost;
} }
} }
return true; return true;
@ -102,7 +103,7 @@ class FunctionCost {
int idxOther= other.getLength() - 1; int idxOther= other.getLength() - 1;
for (; idx >= 0 && idxOther >= 0; idx--, idxOther--) { for (; idx >= 0 && idxOther >= 0; idx--, idxOther--) {
Cost cost= getCost(idx); Cost cost= getCost(idx);
if (cost.getRank() == Rank.NO_MATCH) { if (!cost.converts()) {
haveWorse = true; haveWorse = true;
haveBetter = false; haveBetter = false;
break; break;
@ -155,7 +156,7 @@ class FunctionCost {
int idxOther= other.getLength() - 1; int idxOther= other.getLength() - 1;
for (; idx >= 0 && idxOther >= 0; idx--, idxOther--) { for (; idx >= 0 && idxOther >= 0; idx--, idxOther--) {
Cost cost= getCost(idx); Cost cost= getCost(idx);
if (cost.getRank() == Rank.NO_MATCH) if (!cost.converts())
return true; return true;
Cost otherCost= other.getCost(idxOther); Cost otherCost= other.getCost(idxOther);

View file

@ -101,6 +101,8 @@ public class LookupData {
/** When computing the cost of a method call, treat the first argument as the implied method argument. */ /** When computing the cost of a method call, treat the first argument as the implied method argument. */
public boolean firstArgIsImpliedMethodArg = false; public boolean firstArgIsImpliedMethodArg = false;
public boolean ignoreMembers = false; public boolean ignoreMembers = false;
/** In list-initialization **/
public boolean fNoNarrowing= false;
private ICPPASTParameterDeclaration[] functionParameters; private ICPPASTParameterDeclaration[] functionParameters;
private IASTInitializerClause[] functionArgs; private IASTInitializerClause[] functionArgs;