blob: f28591bda001bba6b4231caf3275418614f65d92 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2004, 2015 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM - Initial API and implementation
* Markus Schorn (Wind River Systems)
* Bryan Wilkinson (QNX)
* Andrew Ferguson (Symbian)
* Sergey Prigogin (Google)
*******************************************************************************/
package org.eclipse.cdt.internal.core.dom.parser.cpp.semantics;
import static org.eclipse.cdt.core.dom.ast.IASTExpression.ValueCategory.LVALUE;
import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.ExpressionTypes.valueCategoryFromReturnType;
import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.ALLCVQ;
import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.COND_TDEF;
import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.CVTYPE;
import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.REF;
import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.TDEF;
import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.addQualifiers;
import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.calculateInheritanceDepth;
import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.getCVQualifier;
import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.getNestedType;
import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.isVoidType;
import java.util.Collections;
import org.eclipse.cdt.core.dom.ast.DOMException;
import org.eclipse.cdt.core.dom.ast.IASTExpression.ValueCategory;
import org.eclipse.cdt.core.dom.ast.IArrayType;
import org.eclipse.cdt.core.dom.ast.IBasicType;
import org.eclipse.cdt.core.dom.ast.IBasicType.Kind;
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.IPointerType;
import org.eclipse.cdt.core.dom.ast.IProblemBinding;
import org.eclipse.cdt.core.dom.ast.IQualifierType;
import org.eclipse.cdt.core.dom.ast.IType;
import org.eclipse.cdt.core.dom.ast.IValue;
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.ICPPEnumeration;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPField;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPFunction;
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.ICPPNamespace;
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.ICPPTemplateArgument;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateInstance;
import org.eclipse.cdt.core.parser.util.ArrayUtil;
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.ITypeContainer;
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.CPPPointerType;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPQualifierType;
import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPEvaluation;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.Cost.DeferredUDC;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.Cost.Rank;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.Cost.ReferenceBinding;
/**
* Routines for calculating the cost of conversions.
*/
public class Conversions {
public enum UDCMode { ALLOWED, FORBIDDEN, DEFER }
public enum Context {
ORDINARY,
IMPLICIT_OBJECT_FOR_METHOD_WITHOUT_REF_QUALIFIER,
IMPLICIT_OBJECT_FOR_METHOD_WITH_REF_QUALIFIER,
FIRST_PARAM_OF_DIRECT_COPY_CTOR,
REQUIRE_DIRECT_BINDING
}
private static final char[] INITIALIZER_LIST_NAME = "initializer_list".toCharArray(); //$NON-NLS-1$
private static final char[] STD_NAME = "std".toCharArray(); //$NON-NLS-1$
/**
* Computes the cost of an implicit conversion sequence [over.best.ics] 13.3.3.1.
* The semantics of the initialization is explained in 8.5-16.
*
* @param target the target (parameter) type
* @param exprType the source (argument) type
* @param valueCat value category of the expression
* @return the cost of converting from source to target
* @throws DOMException
*/
public static Cost checkImplicitConversionSequence(IType target, IType exprType,
ValueCategory valueCat, UDCMode udc, Context ctx) throws DOMException {
final boolean isImpliedObject=
ctx == Context.IMPLICIT_OBJECT_FOR_METHOD_WITHOUT_REF_QUALIFIER ||
ctx == Context.IMPLICIT_OBJECT_FOR_METHOD_WITH_REF_QUALIFIER;
if (isImpliedObject)
udc= UDCMode.FORBIDDEN;
target= getNestedType(target, TDEF);
exprType= getNestedType(exprType, TDEF | REF);
final IType cv1T1= getNestedType(target, TDEF | REF);
final IType T1= getNestedType(cv1T1, TDEF | REF | ALLCVQ);
if (target instanceof ICPPReferenceType) {
ReferenceBinding refBindingType= ReferenceBinding.OTHER_REF;
// [8.5.3-5] initialization of a reference
final boolean isLValueRef= !((ICPPReferenceType) target).isRValueReference();
final IType cv2T2= exprType;
final IType T2= getNestedType(cv2T2, TDEF | REF | ALLCVQ);
refBindingType= isLValueRef ? ReferenceBinding.LVALUE_REF : ReferenceBinding.RVALUE_REF_BINDS_RVALUE;
if (exprType instanceof InitializerListType) {
if (isLValueRef && getCVQualifier(cv1T1) != CVQualifier.CONST)
return Cost.NO_CONVERSION;
Cost cost= listInitializationSequence(((InitializerListType) exprType).getEvaluation(), T1, udc, false);
if (cost.converts()) {
cost.setReferenceBinding(refBindingType);
}
return cost;
}
// If the reference is an lvalue reference and ...
if (isLValueRef) {
// ... the initializer expression is an lvalue (but is not a bit field)
// [for overload resolution bit-fields are treated the same, error if selected as best match]
if (valueCat == LVALUE || ctx == Context.IMPLICIT_OBJECT_FOR_METHOD_WITHOUT_REF_QUALIFIER) {
// 13.3.3.5: For non-static member functions declared without a ref-qualifier,
// an additional rule applies:
// — even if the implicit object parameter is not const-qualified, an rvalue can be
// bound to the parameter as long as in all other respects the argument can be
// converted to the type of the implicit object parameter.
// [Note: The fact that such an argument is an rvalue does not affect the ranking of
// implicit conversion sequences (13.3.3.2). — end note]
if (valueCat != LVALUE)
refBindingType= ReferenceBinding.RVALUE_REF_BINDS_RVALUE;
// ... and "cv1 T1" is reference-compatible with "cv2 T2"
Cost cost= isReferenceCompatible(cv1T1, cv2T2, isImpliedObject);
if (cost != null) {
cost.setReferenceBinding(refBindingType);
return cost;
}
}
// ... or has a class type (i.e., T2 is a class type), where T1 is not reference-related to T2, and can be
// implicitly converted to an lvalue of type 'cv3 T3', where 'cv1 T1' is reference-compatible with
// 'cv3 T3' (this conversion is selected by enumerating the applicable conversion functions (13.3.1.6)
// and choosing the best one through overload resolution (13.3)),
if (T2 instanceof ICPPClassType && udc != UDCMode.FORBIDDEN && isReferenceRelated(T1, T2) < 0) {
Cost cost= initializationByConversionForDirectReference(cv1T1, cv2T2, (ICPPClassType) T2, true, false, ctx);
if (cost != null) {
cost.setReferenceBinding(refBindingType);
return cost;
}
}
}
// Otherwise, the reference shall be an lvalue reference to a non-volatile const type (i.e., cv1
// shall be const), or the reference shall be an rvalue reference.
if (isLValueRef && getCVQualifier(cv1T1) != CVQualifier.CONST) {
return Cost.NO_CONVERSION;
}
// If the initializer expression is an xvalue, class prvalue, array prvalue, or function lvalue
// and 'cv1 T1' is reference-compatible with 'cv2 T2', then the reference is bound to the value
// of the initializer expression (or the appropriate base class subobject).
if (valueCat == ValueCategory.XVALUE
|| (valueCat == ValueCategory.PRVALUE && (T2 instanceof ICPPClassType || T2 instanceof IArrayType))
|| (valueCat == ValueCategory.LVALUE && T2 instanceof ICPPFunctionType)) {
Cost cost = isReferenceCompatible(cv1T1, cv2T2, isImpliedObject);
if (cost != null) {
cost.setReferenceBinding(refBindingType);
return cost;
}
}
// If the initializer expression has class type (i.e. T2 is a class type), where T1 is not
// reference-related to T2, and can be implicitly converted to an xvalue, class prvalue,
// or function lvalue of type 'cv3 T3', where 'cv1 T1' is reference-compatible with 'cv3 T3',
// then the reference is bound to the result of the conversion (or the appropriate base class
// subobject). If the reference is an rvalue reference and the second standard conversion
// sequence of the user-defined conversion sequence includes an lvalue-to-rvalue
// conversion, the program is ill-formed [this is why we pass illFormedIfLValue = true].
if (T2 instanceof ICPPClassType) {
if (udc != UDCMode.FORBIDDEN && isReferenceRelated(T1, T2) < 0) {
Cost cost= initializationByConversionForDirectReference(cv1T1, cv2T2, (ICPPClassType) T2, false, true, ctx);
if (cost != null) {
if (cost != Cost.NO_CONVERSION) {
cost.setReferenceBinding(refBindingType);
}
return cost;
}
}
}
// Otherwise, a temporary of type 'cv1 T1' is created and initialized from the initializer
// expression using the rules for a non-reference copy initialization (8.5). The reference is then
// bound to the temporary.
// 13.3.3.1.7 no temporary object when converting the implicit object parameter
if (!isImpliedObject && ctx != Context.REQUIRE_DIRECT_BINDING) {
Cost cost= nonReferenceConversion(valueCat, cv2T2, T1, udc);
if (cost.converts()) {
cost.setReferenceBinding(refBindingType);
}
boolean referenceRelated = isReferenceRelated(T1, T2) >= 0;
// If T1 is reference-related to T2, cv1 shall be the same cv-qualification as,
// or greater cv-qualification than, cv2.
if (referenceRelated && compareQualifications(cv1T1, cv2T2) < 0) {
return Cost.NO_CONVERSION;
}
// if T1 is reference-related to T2 and the reference is an rvalue reference,
// the initializer expression shall not be an lvalue.
if (referenceRelated && !isLValueRef && valueCat == ValueCategory.LVALUE) {
return Cost.NO_CONVERSION;
}
return cost;
}
return Cost.NO_CONVERSION;
}
// Non-reference binding
return nonReferenceConversion(valueCat, exprType, T1, udc);
}
/**
* C++0x: 13.3.1.6 Initialization by conversion function for direct reference binding
* @param needLValue don't consider conversion functions that return rvalue references
* @param illFormedIfLValue make the conversion ill-formed (by returning Cost.NO_CONVERSION)
* if the best match is a conversion function that returns an
* lvalue reference
* Note that there's a difference between returning null and returning Cost.NO_CONVERSION:
* in the former case, the caller will continue trying other conversion methods.
*/
private static Cost initializationByConversionForDirectReference(final IType cv1T1, final IType cv2T2, final ICPPClassType T2,
boolean needLValue, boolean illFormedIfLValue, Context ctx)
throws DOMException {
ICPPMethod[] fcns= SemanticUtil.getConversionOperators(T2);
Cost operatorCost= null;
FunctionCost bestUdcCost= null;
boolean ambiguousConversionOperator= false;
if (fcns.length > 0 && !(fcns[0] instanceof IProblemBinding)) {
for (final ICPPMethod op : fcns) {
// Note: the special case of initializing a temporary to be bound to the first parameter
// of a copy constructor called with a single argument in the context of direct-initialization
// is (more naturally) handled here rather than in copyInitializationOfClass().
if (op.isExplicit() && ctx != Context.FIRST_PARAM_OF_DIRECT_COPY_CTOR)
continue;
final ICPPFunctionType ft = op.getType();
IType t= getNestedType(ft.getReturnType(), TDEF);
final boolean isLValueRef= t instanceof ICPPReferenceType && !((ICPPReferenceType) t).isRValueReference();
if (needLValue && !isLValueRef) {
continue;
}
IType implicitParameterType= CPPSemantics.getImplicitParameterType(op);
Cost udcCost= isReferenceCompatible(getNestedType(implicitParameterType, TDEF | REF), cv2T2, true); // expression type to implicit object type
if (udcCost != null) {
// Make sure top-level cv-qualifiers are compared
udcCost.setReferenceBinding(ReferenceBinding.LVALUE_REF);
FunctionCost udcFuncCost= new FunctionCost(op, udcCost);
int cmp= udcFuncCost.compareTo(null, bestUdcCost);
if (cmp <= 0) {
Cost cost= isReferenceCompatible(cv1T1, getNestedType(t, TDEF | REF), false); // converted to target
if (cost != null) {
bestUdcCost= udcFuncCost;
ambiguousConversionOperator= cmp == 0;
operatorCost= cost;
operatorCost.setUserDefinedConversion(op);
if (illFormedIfLValue && isLValueRef) {
operatorCost = Cost.NO_CONVERSION;
}
}
}
}
}
}
if (operatorCost != null && !ambiguousConversionOperator) {
return operatorCost;
}
return null;
}
/**
* 8.5-16
*/
private static Cost nonReferenceConversion(ValueCategory valueCat, IType source, IType target, UDCMode udc) throws DOMException {
if (source instanceof InitializerListType) {
return listInitializationSequence(((InitializerListType) source).getEvaluation(), target, udc, false);
}
IType uqTarget= SemanticUtil.getNestedType(target, TDEF | REF | CVTYPE);
IType uqSource= SemanticUtil.getNestedType(source, TDEF | REF | CVTYPE);
if (uqTarget instanceof ICPPClassType) {
if (uqSource instanceof ICPPClassType) {
// 13.3.3.1-6 Conceptual derived to base conversion
int depth= calculateInheritanceDepth(uqSource, uqTarget);
if (depth >= 0) {
if (depth == 0) {
return new Cost(source, target, Rank.IDENTITY);
}
Cost cost= new Cost(source, target, Rank.CONVERSION);
cost.setInheritanceDistance(depth);
return cost;
}
}
if (udc == UDCMode.FORBIDDEN)
return Cost.NO_CONVERSION;
return copyInitializationOfClass(valueCat, source, (ICPPClassType) uqTarget, udc == UDCMode.DEFER);
}
if (uqSource instanceof ICPPClassType) {
if (udc == UDCMode.FORBIDDEN)
return Cost.NO_CONVERSION;
return initializationByConversion(valueCat, source, (ICPPClassType) uqSource, target, udc == UDCMode.DEFER, false);
}
return checkStandardConversionSequence(uqSource, target);
}
/**
* Get those fields of 'targetClass' which participate in aggregate initialization.
* These are the declared fields, excluding static fields and anonymous bit-fields
* ([decl.init.aggr] p6).
*/
static ICPPField[] getFieldsForAggregateInitialization(ICPPClassType targetClass) {
ICPPField[] fields = targetClass.getDeclaredFields();
ICPPField[] result = fields;
int j = 0;
for (int i = 0; i < fields.length; ++i) {
// TODO: Check for anonymous bit-fields. ICPPField doesn't currently expose whether
// it's a bit-field.
if (fields[i].isStatic()) {
if (fields == result) {
result = new ICPPField[fields.length - 1];
System.arraycopy(fields, 0, result, 0, i);
}
} else if (fields != result) {
result[j] = fields[i];
++j;
}
}
return ArrayUtil.trim(result);
}
/**
* Checks whether 'targetClass' can be initialized from 'list' according to the rules for
* aggregate initialization ([dcl.init.aggr]).
*/
static boolean checkAggregateInitialization(EvalInitList list, ICPPClassType targetClass)
throws DOMException {
ICPPField[] fields = getFieldsForAggregateInitialization(targetClass);
ICPPEvaluation[] initializers = list.getClauses();
// p7: An initializer-list is ill-formed if the number of initializer-clauses exceeds
// the number of members to initialize.
if (initializers.length > fields.length) {
return false;
}
// p3: The elements of the initializer list are taken as initializers for the elements
// of the aggregate, in order.
int i = 0;
for (; i < initializers.length; ++i) {
ICPPEvaluation initializer = initializers[i];
ICPPField field = fields[i];
// Each element is copy-initialized from the corresponding initializer-clause.
Cost cost = checkImplicitConversionSequence(field.getType(), initializer.getType(),
initializer.getValueCategory(), UDCMode.ALLOWED, Context.ORDINARY);
if (!cost.converts()) {
return false;
}
// If the initializer-clause is an expression and a narrowing conversion is
// required to convert the expression, the program is ill-formed.
if (!(initializer instanceof EvalInitList) && cost.isNarrowingConversion()) {
return false;
}
}
// p8: If there are fewer initializer-clauses than there are elements in the
// aggregate, then each element not explicitly initialized shall be
// initialized from its default member initializer or, if there is no
// default member initializer, from an empty initializer list.
for (; i < fields.length; ++i) {
ICPPField field = fields[i];
IValue initialValue = field.getInitialValue();
if (initialValue != null) {
continue; // has a default member initializer
}
// p11: If an incomplete or empty initializer-list leaves a member of
// reference type uninitialized, the program is ill-formed.
IType fieldType = SemanticUtil.getNestedType(field.getType(), TDEF);
if (fieldType instanceof ICPPReferenceType) {
return false;
}
// Empty initializer list
EvalInitList emptyInit = new EvalInitList(ICPPEvaluation.EMPTY_ARRAY,
CPPSemantics.getCurrentLookupPoint());
Cost cost = listInitializationSequence(emptyInit, fieldType, UDCMode.ALLOWED, false);
if (!cost.converts()) {
return false;
}
}
// TODO: Implement brace elision rules.
return true;
}
/**
* 13.3.3.1.5 List-initialization sequence [over.ics.list]
*/
static Cost listInitializationSequence(EvalInitList arg, IType target, UDCMode udc, boolean isDirect) throws DOMException {
Cost result = listInitializationSequenceHelper(arg, target, udc, isDirect);
result.setListInitializationTarget(target);
return result;
}
static Cost listInitializationSequenceHelper(EvalInitList arg, IType target, UDCMode udc, boolean isDirect) throws DOMException {
IType listType= getInitListType(target);
if (listType == null && target instanceof IArrayType) {
Number arraySize = ((IArrayType) target).getSize().numberValue();
if (arraySize != null) {
IType elementType = ((IArrayType) target).getType();
// TODO(nathanridge): If there are fewer initializer clauses than the array size,
// then the element type is required to be default-constructible.
if (arg.getClauses().length <= arraySize.longValue()) {
listType = elementType;
}
}
}
if (listType != null) {
ICPPEvaluation[] clauses = arg.getClauses();
Cost worstCost= new Cost(arg.getType(), target, Rank.IDENTITY);
for (ICPPEvaluation clause : clauses) {
Cost cost= checkImplicitConversionSequence(listType, clause.getType(),
clause.getValueCategory(), UDCMode.ALLOWED, Context.ORDINARY);
if (!cost.converts())
return cost;
if (cost.isNarrowingConversion()) {
cost.setRank(Rank.NO_MATCH);
return cost;
}
if (cost.compareTo(worstCost) > 0) {
worstCost= cost;
}
}
return worstCost;
}
IType noCVTarget= getNestedType(target, CVTYPE | TDEF);
if (noCVTarget instanceof ICPPClassType) {
if (udc == UDCMode.FORBIDDEN)
return Cost.NO_CONVERSION;
ICPPClassType classTarget= (ICPPClassType) noCVTarget;
if (TypeTraits.isAggregateClass(classTarget) && checkAggregateInitialization(arg, classTarget)) {
Cost cost= new Cost(arg.getType(), target, Rank.IDENTITY);
cost.setUserDefinedConversion(null);
return cost;
}
return listInitializationOfClass(arg, classTarget, isDirect, udc == UDCMode.DEFER);
}
ICPPEvaluation[] args = arg.getClauses();
if (args.length == 1) {
final ICPPEvaluation firstArg = args[0];
if (!firstArg.isInitializerList()) {
Cost cost= checkImplicitConversionSequence(target, firstArg.getType(), firstArg.getValueCategory(), udc, Context.ORDINARY);
if (cost.isNarrowingConversion()) {
return Cost.NO_CONVERSION;
}
return cost;
}
} else if (args.length == 0) {
return new Cost(arg.getType(), target, Rank.IDENTITY);
}
return Cost.NO_CONVERSION;
}
static IType getInitListType(IType target) {
if (target instanceof ICPPClassType && target instanceof ICPPTemplateInstance) {
ICPPTemplateInstance inst = (ICPPTemplateInstance) target;
if (CharArrayUtils.equals(INITIALIZER_LIST_NAME, inst.getNameCharArray())) {
IBinding owner = inst.getOwner();
if (owner instanceof ICPPNamespace
&& CharArrayUtils.equals(STD_NAME, owner.getNameCharArray())
&& owner.getOwner() == null) {
ICPPTemplateArgument[] args = inst.getTemplateArguments();
if (args.length == 1) {
ICPPTemplateArgument arg = args[0];
if (arg.isTypeValue()) {
return arg.getTypeValue();
}
}
}
}
}
return null;
}
/**
* [3.9.3-4] Implements cv-ness (partial) comparison. There is a (partial)
* ordering on cv-qualifiers, so that a type can be said to be more
* cv-qualified than another.
* @return <ul>
* <li>3 if cv1 == const volatile cv2
* <li>2 if cv1 == volatile cv2
* <li>1 if cv1 == const cv2
* <li>EQ 0 if cv1 == cv2
* <li>LT -1 if cv1 is less qualified than cv2 or not comparable
* </ul>
*/
private static final int compareQualifications(IType t1, IType t2) {
return getCVQualifier(t1).partialComparison(getCVQualifier(t2));
}
/**
* [8.5.3] "cv1 T1" is reference-related to "cv2 T2" if T1 is the same type as T2,
* or T1 is a base class of T2.
* Note this is not a symmetric relation.
* @return inheritance distance, or -1, if <code>cv1t1</code> is not reference-related to <code>cv2t2</code>
*/
private static final int isReferenceRelated(IType cv1Target, IType cv2Source) {
IType t= SemanticUtil.getNestedType(cv1Target, TDEF | REF);
IType s= SemanticUtil.getNestedType(cv2Source, TDEF | REF);
// The way cv-qualification is currently modeled means
// we must cope with IPointerType objects separately.
if (t instanceof IPointerType) {
if (s instanceof IPointerType) {
t= SemanticUtil.getNestedType(((IPointerType) t).getType(), TDEF | REF);
s= SemanticUtil.getNestedType(((IPointerType) s).getType(), TDEF | REF);
} else {
return -1;
}
} else if (t instanceof IArrayType) {
if (s instanceof IArrayType) {
final IArrayType at = (IArrayType) t;
final IArrayType st = (IArrayType) s;
final IValue av= at.getSize();
final IValue sv= st.getSize();
if (av == sv || (av != null && av.equals(sv))) {
t= SemanticUtil.getNestedType(at.getType(), TDEF | REF | ALLCVQ);
s= SemanticUtil.getNestedType(st.getType(), TDEF | REF | ALLCVQ);
} else {
return -1;
}
} else {
return -1;
}
} else {
if (t instanceof IQualifierType)
t= SemanticUtil.getNestedType(((IQualifierType) t).getType(), TDEF | REF);
if (s instanceof IQualifierType)
s= SemanticUtil.getNestedType(((IQualifierType) s).getType(), TDEF | REF);
if (t instanceof ICPPClassType && s instanceof ICPPClassType) {
return SemanticUtil.calculateInheritanceDepth(s, t);
}
}
if (t == s || (t != null && s != null && t.isSameType(s))) {
return 0;
}
return -1;
}
/**
* [8.5.3] "cv1 T1" is reference-compatible with "cv2 T2" if T1 is reference-related
* to T2 and cv1 is the same cv-qualification as, or greater cv-qualification than, cv2.
* Note this is not a symmetric relation.
* @return The cost for converting or <code>null</code> if <code>cv1t1</code> is not
* reference-compatible with <code>cv2t2</code>
*/
private static final Cost isReferenceCompatible(IType cv1Target, IType cv2Source, boolean isImpliedObject) {
int inheritanceDist= isReferenceRelated(cv1Target, cv2Source);
if (inheritanceDist < 0)
return null;
final int cmp= compareQualifications(cv1Target, cv2Source);
if (cmp < 0)
return null;
Cost cost= new Cost(cv2Source, cv1Target, Rank.IDENTITY);
cost.setQualificationAdjustment(cmp);
if (inheritanceDist > 0) {
cost.setInheritanceDistance(inheritanceDist);
cost.setRank(Rank.CONVERSION);
}
if (isImpliedObject) {
cost.setImpliedObject();
}
return cost;
}
/**
* [4] Standard Conversions
* Computes the cost of using the standard conversion sequence from source to target.
*/
private static final Cost checkStandardConversionSequence(IType source, IType target) {
final Cost cost= new Cost(source, target, Rank.IDENTITY);
if (lvalue_to_rvalue(cost))
return cost;
if (promotion(cost))
return cost;
if (conversion(cost))
return cost;
if (qualificationConversion(cost))
return cost;
// If we can't convert the qualifications, then we can't do anything
cost.setRank(Rank.NO_MATCH);
return cost;
}
// [over.match.list] Initialization by list-initialization
static Cost listInitializationOfClass(EvalInitList arg, ICPPClassType t, boolean isDirect, boolean deferUDC) throws DOMException {
if (deferUDC) {
Cost c= new Cost(arg.getType(), t, Rank.USER_DEFINED_CONVERSION);
c.setDeferredUDC(isDirect ? DeferredUDC.DIRECT_LIST_INIT_OF_CLASS : DeferredUDC.LIST_INIT_OF_CLASS);
return c;
}
// p1: When objects of non-aggregate class type are list-initialized,
// [...] overload resoution selects the constructor in two phases:
// - Initially, the candidate functions are the initializer-
// list constructors of the class T and the argument list
// consists of the initializer list as a single argument.
ICPPConstructor usedCtor= null;
Cost bestCost= null;
final ICPPConstructor[] constructors = t.getConstructors();
ICPPConstructor[] ctors= constructors;
for (ICPPConstructor ctor : ctors) {
final int minArgCount = ctor.getRequiredArgumentCount();
if (minArgCount == 0) {
if (arg.getClauses().length == 0) {
Cost c= new Cost(arg.getType(), t, Rank.IDENTITY);
c.setUserDefinedConversion(ctor);
return c;
}
} else if (minArgCount <= 1) {
IType[] parTypes= ctor.getType().getParameterTypes();
if (parTypes.length > 0) {
final IType target = parTypes[0];
if (getInitListType(target) != null) {
Cost cost= listInitializationSequence(arg, target, UDCMode.FORBIDDEN, isDirect);
if (cost.converts()) {
int cmp= cost.compareTo(bestCost);
if (bestCost == null || cmp < 0) {
usedCtor= ctor;
cost.setUserDefinedConversion(ctor);
bestCost= cost;
} else if (cmp == 0) {
bestCost.setAmbiguousUDC(true);
}
}
}
}
}
}
if (bestCost != null) {
if (!bestCost.isAmbiguousUDC() && !isDirect) {
if (usedCtor != null && usedCtor.isExplicit()) {
bestCost.setRank(Rank.NO_MATCH);
}
}
// This cost came from listInitializationSequence() with an std::initializer_list
// type as the list initialization target. From the point of view of the caller,
// however, the target is the class type, not std::initializer_list, so update it
// accordingly.
bestCost.setListInitializationTarget(t);
return bestCost;
}
// - If no viable initializer-list constructor is found,
// overload resolution is performed again, where the
// candidate functions are all the constructors of the
// class T and the argument list consists of the elements
// of the initializer list.
LookupData data= new LookupData(t.getNameCharArray(), null, CPPSemantics.getCurrentLookupPoint());
final ICPPEvaluation[] expandedArgs = arg.getClauses();
data.setFunctionArguments(false, 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, false);
final Cost c;
if (result instanceof ICPPMethod) {
c= new Cost(arg.getType(), t, Rank.IDENTITY);
c.setUserDefinedConversion((ICPPMethod) result);
} else if (result instanceof IProblemBinding
&& ((IProblemBinding) result).getID() == IProblemBinding.SEMANTIC_AMBIGUOUS_LOOKUP) {
c = new Cost(arg.getType(), t, Rank.USER_DEFINED_CONVERSION);
c.setAmbiguousUDC(true);
} else {
c= Cost.NO_CONVERSION;
}
// This cost came from listInitializationSequence() with an std::initializer_list
// type as the list initialization target. From the point of view of the caller,
// however, the target is the class type, not std::initializer_list, so update it
// accordingly.
c.setListInitializationTarget(t);
return c;
}
/**
* 13.3.1.4 Copy-initialization of class by user-defined conversion [over.match.copy]
*/
static final Cost copyInitializationOfClass(ValueCategory valueCat, IType source, ICPPClassType t,
boolean deferUDC) throws DOMException {
if (deferUDC) {
Cost c= new Cost(source, t, Rank.USER_DEFINED_CONVERSION);
c.setDeferredUDC(DeferredUDC.COPY_INIT_OF_CLASS);
return c;
}
FunctionCost cost1= null;
Cost cost2= null;
ICPPFunction[] ctors= t.getConstructors();
ctors = CPPTemplates.instantiateForFunctionCall(ctors, null,
Collections.singletonList(source), Collections.singletonList(valueCat), false);
for (ICPPFunction f : ctors) {
if (!(f instanceof ICPPConstructor) || f instanceof IProblemBinding)
continue;
ICPPConstructor ctor= (ICPPConstructor) f;
// Note: the special case of initializing a temporary to be bound to the first parameter
// of a copy constructor called with a single argument in the context of direct-initialization
// is (more naturally) handled in initializationByConversionForDirectReference.
if (!ctor.isExplicit()) {
final ICPPFunctionType ft = ctor.getType();
final IType[] ptypes = ft.getParameterTypes();
FunctionCost c1;
if (ptypes.length == 0) {
if (ctor.takesVarArgs()) {
c1= new FunctionCost(ctor, new Cost(source, null, Rank.ELLIPSIS_CONVERSION));
} else {
continue;
}
} else {
IType ptype= SemanticUtil.getNestedType(ptypes[0], TDEF);
// We don't need to check the implicit conversion sequence if the type is void
if (SemanticUtil.isVoidType(ptype))
continue;
if (ctor.getRequiredArgumentCount() > 1)
continue;
c1= new FunctionCost(ctor, checkImplicitConversionSequence(ptype, source, valueCat, UDCMode.FORBIDDEN, Context.ORDINARY));
}
int cmp= c1.compareTo(null, cost1);
if (cmp <= 0) {
cost1= c1;
cost2= new Cost(t, t, Rank.IDENTITY);
cost2.setUserDefinedConversion(ctor);
if (cmp == 0) {
cost2.setAmbiguousUDC(true);
}
}
}
}
final IType uqSource= getNestedType(source, TDEF | REF | CVTYPE);
if (uqSource instanceof ICPPClassType) {
ICPPFunction[] ops = SemanticUtil.getConversionOperators((ICPPClassType) uqSource);
ops= CPPTemplates.instantiateConversionTemplates(ops, t);
for (final ICPPFunction f : ops) {
if (f instanceof ICPPMethod && !(f instanceof IProblemBinding)) {
ICPPMethod op= (ICPPMethod) f;
if (op.isExplicit())
continue;
final IType returnType = op.getType().getReturnType();
final IType uqReturnType= getNestedType(returnType, REF | TDEF | CVTYPE);
final int dist = SemanticUtil.calculateInheritanceDepth(uqReturnType, t);
if (dist >= 0) {
IType implicitType= CPPSemantics.getImplicitParameterType(op);
final Cost udcCost = isReferenceCompatible(getNestedType(implicitType, TDEF | REF), source, true);
if (udcCost != null) {
// Make sure top-level cv-qualifiers are compared
udcCost.setReferenceBinding(ReferenceBinding.LVALUE_REF);
FunctionCost c1= new FunctionCost(op, udcCost);
int cmp= c1.compareTo(null, 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.getCost(0).converts())
return Cost.NO_CONVERSION;
return cost2;
}
/**
* 13.3.1.5 Initialization by conversion function [over.match.conv]
*/
static Cost initializationByConversion(ValueCategory valueCat, IType source, ICPPClassType uqSource,
IType target, boolean deferUDC, boolean allowExplicitConversion) throws DOMException {
if (deferUDC) {
Cost c= new Cost(source, target, Rank.USER_DEFINED_CONVERSION);
c.setDeferredUDC(DeferredUDC.INIT_BY_CONVERSION);
return c;
}
ICPPFunction[] ops = SemanticUtil.getConversionOperators(uqSource);
ops= CPPTemplates.instantiateConversionTemplates(ops, target);
FunctionCost cost1= null;
Cost cost2= null;
for (final ICPPFunction f : ops) {
if (f instanceof ICPPMethod && !(f instanceof IProblemBinding)) {
ICPPMethod op= (ICPPMethod) f;
final boolean isExplicitConversion= op.isExplicit() && !allowExplicitConversion;
if (isExplicitConversion /** && !direct **/)
continue;
ICPPFunctionType functionType = op.getType();
final IType returnType = functionType.getReturnType();
IType uqReturnType= getNestedType(returnType, TDEF | ALLCVQ);
Cost c2= checkImplicitConversionSequence(target, uqReturnType, valueCategoryFromReturnType(uqReturnType), UDCMode.FORBIDDEN, Context.ORDINARY);
if (c2.converts()) {
if (isExplicitConversion && c2.getRank() != Rank.IDENTITY)
continue;
IType implicitType= CPPSemantics.getImplicitParameterType(op);
final Cost udcCost = isReferenceCompatible(getNestedType(implicitType, TDEF | REF), source, true);
if (udcCost != null) {
// Make sure top-level cv-qualifiers are compared
if (functionType.hasRefQualifier() && functionType.isRValueReference()) {
udcCost.setReferenceBinding(ReferenceBinding.RVALUE_REF_BINDS_RVALUE);
} else {
udcCost.setReferenceBinding(ReferenceBinding.LVALUE_REF);
}
FunctionCost c1= new FunctionCost(op, udcCost);
int cmp= c1.compareTo(null, cost1);
if (cmp <= 0) {
cost1= c1;
cost2= c2;
cost2.setUserDefinedConversion(op);
if (cmp == 0) {
cost2.setAmbiguousUDC(true);
}
}
}
}
}
}
if (cost1 == null || !cost1.getCost(0).converts())
return Cost.NO_CONVERSION;
return cost2;
}
/**
* Attempts the conversions below and returns whether this completely converts the source to
* the target type.
* [4.1] Lvalue-to-rvalue conversion
* [4.2] array-to-ptr
* [4.3] function-to-ptr
*/
private static final boolean lvalue_to_rvalue(final Cost cost) {
IType target = getNestedType(cost.target, REF | TDEF | ALLCVQ);
IType source= getNestedType(cost.source, REF | TDEF);
// 4.2 array to pointer conversion
if (source instanceof IArrayType) {
if (target instanceof IPointerType) {
// 4.2-2 a string literal can be converted to pointer to char
source = unqualifyStringLiteral(source, (IPointerType) target, cost);
}
if (!(source instanceof IPointerType)) {
source = new CPPPointerType(getNestedType(((IArrayType) source).getType(), TDEF));
}
} else if (source instanceof IFunctionType) {
// 4.3 function to pointer conversion
source = new CPPPointerType(source);
} else {
if (source instanceof IPointerType) {
// A string literal may have been converted to a pointer when
// computing the type of a conditional expression.
if (target instanceof IPointerType) {
// 4.2-2 a string literal can be converted to pointer to char
source = unqualifyStringLiteral(source, (IPointerType) target, cost);
}
}
source = getNestedType(source, TDEF | REF | ALLCVQ);
}
if (source == null || target == null) {
cost.setRank(Rank.NO_MATCH);
return true;
}
cost.source= source;
cost.target= target;
return source.isSameType(target);
}
private static IType unqualifyStringLiteral(IType source, final IPointerType target, final Cost cost) {
if (target instanceof ICPPPointerToMemberType)
return source;
final IType targetPtrTgt= getNestedType((target).getType(), TDEF);
if (targetPtrTgt instanceof IQualifierType && ((IQualifierType) targetPtrTgt).isConst())
return source;
IType srcTarget= ((ITypeContainer) source).getType();
if (!(srcTarget instanceof IQualifierType))
return source;
final IQualifierType srcQTarget= (IQualifierType) srcTarget;
if (srcQTarget.isConst() && !srcQTarget.isVolatile()) {
srcTarget= srcQTarget.getType();
if (srcTarget instanceof CPPBasicType) {
if (((CPPBasicType) srcTarget).isFromStringLiteral()) {
source= new CPPPointerType(srcTarget, false, false, false);
CVQualifier cvqTarget = getCVQualifier(targetPtrTgt).add(CVQualifier.CONST);
cost.setQualificationAdjustment(cvqTarget.partialComparison(CVQualifier.NONE) << 3);
}
}
}
return source;
}
/**
* [4.4] Qualifications
* @param cost
*/
private static final boolean qualificationConversion(Cost cost) {
IType s = cost.source;
IType t = cost.target;
boolean constInEveryCV2k = true;
boolean firstPointer= true;
int adjustments= 0;
int shift=0;
while (true) {
s= getNestedType(s, TDEF | REF);
t= getNestedType(t, TDEF | REF);
if (s instanceof IPointerType && t instanceof IPointerType) {
final int cmp= compareQualifications(t, s); // is t more qualified than s?
if (cmp < 0 || (cmp > 0 && !constInEveryCV2k)) {
return false;
}
final IPointerType tPtr = (IPointerType) t;
final IPointerType sPtr = (IPointerType) s;
if (haveMemberPtrConflict(sPtr, tPtr))
return false;
constInEveryCV2k &= (firstPointer || tPtr.isConst());
s= sPtr.getType();
t= tPtr.getType();
firstPointer= false;
adjustments |= (cmp << shift);
shift+= 3;
} else {
break;
}
}
int cmp= compareQualifications(t, s); // is t more qualified than s?
if (cmp < 0 || (cmp > 0 && !constInEveryCV2k)) {
return false;
}
adjustments |= (cmp << shift);
s= getNestedType(s, ALLCVQ | TDEF | REF);
t= getNestedType(t, ALLCVQ | TDEF | REF);
if (adjustments > 0) {
cost.setQualificationAdjustment(adjustments);
}
return s != null && t != null && s.isSameType(t);
}
private static boolean haveMemberPtrConflict(IPointerType s, IPointerType t) {
final boolean sIsPtrToMember = s instanceof ICPPPointerToMemberType;
final boolean tIsPtrToMember = t instanceof ICPPPointerToMemberType;
if (sIsPtrToMember != tIsPtrToMember) {
return true;
}
if (sIsPtrToMember) {
final IType sMemberOf = ((ICPPPointerToMemberType) s).getMemberOfClass();
final IType tMemberOf = ((ICPPPointerToMemberType) t).getMemberOfClass();
if (sMemberOf == null || tMemberOf == null || !sMemberOf.isSameType(tMemberOf)) {
return true;
}
}
return false;
}
/**
* Attempts promotions and returns whether the promotion converted the type.
*
* [4.5] [4.6] Promotion
*
* 4.5-1 char, signed char, unsigned char, short int or unsigned short int
* can be converted to int if int can represent all the values of the source
* type, otherwise they can be converted to unsigned int.
* 4.5-2 wchar_t or an enumeration can be converted to the first of the
* following that can hold it: int, unsigned int, long unsigned long.
* 4.5-4 bool can be promoted to int
* 4.6 float can be promoted to double
*/
private static final boolean promotion(Cost cost) {
IType src = cost.source;
IType trg = cost.target;
boolean canPromote= false;
if (trg instanceof IBasicType) {
IBasicType basicTgt = (IBasicType) trg;
final Kind tKind = basicTgt.getKind();
if (src instanceof ICPPEnumeration) {
final ICPPEnumeration enumType = (ICPPEnumeration) src;
if (enumType.isScoped()) {
return false;
}
IType fixedType= enumType.getFixedType();
if (fixedType == null) {
if (tKind == Kind.eInt || tKind == Kind.eUnspecified) {
if (trg instanceof ICPPBasicType) {
int qualifiers = ArithmeticConversion.getEnumIntTypeModifiers((IEnumeration) src);
int targetModifiers = ((ICPPBasicType) trg).getModifiers();
if (qualifiers == (targetModifiers & (IBasicType.IS_LONG | IBasicType.IS_LONG_LONG | IBasicType.IS_SHORT | IBasicType.IS_UNSIGNED))) {
canPromote = true;
}
} else {
canPromote = true;
}
}
} else {
if (fixedType.isSameType(trg))
canPromote= true;
// Allow to further promote the fixed type
src= fixedType;
}
}
if (src instanceof IBasicType) {
final IBasicType basicSrc = (IBasicType) src;
Kind sKind = basicSrc.getKind();
if (tKind == Kind.eInt) {
if (!basicTgt.isLong() && !basicTgt.isLongLong() && !basicTgt.isShort()) {
switch (sKind) {
case eInt: // short, and unsigned short
if (basicSrc.isShort() && !basicTgt.isUnsigned()) {
canPromote= true;
}
break;
case eChar:
case eBoolean:
case eWChar:
case eChar16:
case eUnspecified: // treat unspecified as int
if (!basicTgt.isUnsigned()) {
canPromote= true;
}
break;
case eChar32:
if (basicTgt.isUnsigned()) {
canPromote= true;
}
break;
default:
break;
}
}
} else if (tKind == Kind.eDouble && sKind == Kind.eFloat) {
canPromote= true;
}
}
}
if (canPromote) {
cost.setRank(Rank.PROMOTION);
return true;
}
return false;
}
/**
* Attempts conversions and returns whether the conversion succeeded.
* [4.7] Integral conversions
* [4.8] Floating point conversions
* [4.9] Floating-integral conversions
* [4.10] Pointer conversions
* [4.11] Pointer to member conversions
*/
private static final boolean conversion(Cost cost) {
final IType s = cost.source;
final IType t = cost.target;
if (t instanceof IBasicType) {
// 4.7 integral conversion
// 4.8 floating point conversion
// 4.9 floating-integral conversion
final Kind tgtKind = ((IBasicType) t).getKind();
if (s instanceof IBasicType) {
final Kind srcKind = ((IBasicType) s).getKind();
if (srcKind == Kind.eVoid)
return false;
// 4.12 std::nullptr_t can be converted to bool
if (srcKind == Kind.eNullPtr && tgtKind != Kind.eBoolean)
return false;
// 4.10-1 a null pointer constant can be converted to std::nullptr_t
if (tgtKind == Kind.eNullPtr && !isNullPointerConstant(s))
return false;
cost.setRank(Rank.CONVERSION);
if (srcKind != Kind.eNullPtr && tgtKind != Kind.eNullPtr) {
cost.setCouldNarrow();
}
return true;
}
if (s instanceof ICPPEnumeration && !((ICPPEnumeration) s).isScoped()) {
// 4.7 An rvalue of an enumeration type can be converted to an rvalue of an integer type.
cost.setRank(Rank.CONVERSION);
cost.setCouldNarrow();
return true;
}
// 4.12 pointer or pointer to member type can be converted to an rvalue of type bool
if (tgtKind == Kind.eBoolean && s instanceof IPointerType) {
cost.setRank(Rank.CONVERSION_PTR_BOOL);
return true;
}
}
if (t instanceof IPointerType) {
IPointerType tgtPtr= (IPointerType) t;
// 4.10-1 an integral constant expression of integer type that evaluates to 0 can
// be converted to a pointer type
// 4.11-1 same for pointer to member
if (s instanceof IBasicType) {
if (isNullPointerConstant(s)) {
cost.setRank(Rank.CONVERSION);
return true;
}
return false;
}
if (s instanceof IPointerType) {
IPointerType srcPtr= (IPointerType) s;
// 4.10-2 an rvalue of type "pointer to cv T", where T is an object type can be
// converted to an rvalue of type "pointer to cv void"
IType tgtPtrTgt= getNestedType(tgtPtr.getType(), TDEF | CVTYPE | REF);
if (SemanticUtil.isVoidType(tgtPtrTgt)) {
cost.setRank(Rank.CONVERSION);
cost.setInheritanceDistance(Short.MAX_VALUE);
CVQualifier cv= getCVQualifier(srcPtr.getType());
cost.source= new CPPPointerType(addQualifiers(CPPSemantics.VOID_TYPE, cv.isConst(), cv.isVolatile(), cv.isRestrict()));
return false;
}
final boolean tIsPtrToMember = t instanceof ICPPPointerToMemberType;
final boolean sIsPtrToMember = s instanceof ICPPPointerToMemberType;
if (!tIsPtrToMember && !sIsPtrToMember) {
// 4.10-3 An rvalue of type "pointer to cv D", where D is a class type can be converted
// to an rvalue of type "pointer to cv B", where B is a base class of D.
IType srcPtrTgt= getNestedType(srcPtr.getType(), TDEF | CVTYPE | REF);
if (tgtPtrTgt instanceof ICPPClassType && srcPtrTgt instanceof ICPPClassType) {
int depth= SemanticUtil.calculateInheritanceDepth(srcPtrTgt, tgtPtrTgt);
if (depth == -1) {
cost.setRank(Rank.NO_MATCH);
return true;
}
if (depth > 0) {
cost.setRank(Rank.CONVERSION);
cost.setInheritanceDistance(depth);
CVQualifier cv= getCVQualifier(srcPtr.getType());
cost.source= new CPPPointerType(addQualifiers(tgtPtrTgt, cv.isConst(), cv.isVolatile(), cv.isRestrict()));
}
return false;
}
} else if (tIsPtrToMember && sIsPtrToMember) {
// 4.11-2 An rvalue of type "pointer to member of B of type cv T", where B is a class type,
// can be converted to an rvalue of type "pointer to member of D of type cv T" where D is a
// derived class of B
ICPPPointerToMemberType spm = (ICPPPointerToMemberType) s;
ICPPPointerToMemberType tpm = (ICPPPointerToMemberType) t;
IType st = spm.getType();
IType tt = tpm.getType();
if (st != null && tt != null && st.isSameType(tt)) {
int depth = SemanticUtil.calculateInheritanceDepth(tpm.getMemberOfClass(),
spm.getMemberOfClass());
if (depth == -1) {
cost.setRank(Rank.NO_MATCH);
return true;
}
if (depth > 0) {
cost.setRank(Rank.CONVERSION);
cost.setInheritanceDistance(depth);
cost.source = new CPPPointerToMemberType(spm.getType(),
tpm.getMemberOfClass(), spm.isConst(), spm.isVolatile(), spm.isRestrict());
}
return false;
}
}
}
}
return false;
}
public static boolean isNullPointerConstant(IType s) {
if (s instanceof CPPBasicType) {
final CPPBasicType basicType = (CPPBasicType) s;
if (basicType.getKind() == Kind.eNullPtr)
return true;
Long val = basicType.getAssociatedNumericalValue();
if (val != null && val == 0) {
return true;
}
}
return false;
}
/**
* 4.1, 4.2, 4.3
*/
public static IType lvalue_to_rvalue(IType type, boolean resolveTypedefs) {
IType t= SemanticUtil.getNestedType(type, TDEF | REF);
if (t instanceof IArrayType) {
return new CPPPointerType(((IArrayType) t).getType());
}
if (t instanceof IFunctionType) {
return new CPPPointerType(t);
}
IType uqType= SemanticUtil.getNestedType(t, TDEF | REF | ALLCVQ);
if (uqType instanceof ICPPClassType) {
return resolveTypedefs ? t : SemanticUtil.getNestedType(type, COND_TDEF | REF);
}
return resolveTypedefs ? uqType : SemanticUtil.getNestedType(type, COND_TDEF | REF | ALLCVQ);
}
/**
* Composite pointer type computed as described in 5.9-2 except that if the conversion to
* the pointer is not possible, the method returns {@code null}.
*/
public static IType compositePointerType(IType t1, IType t2) {
t1 = SemanticUtil.getNestedType(t1, TDEF);
t2 = SemanticUtil.getNestedType(t2, TDEF);
final boolean isPtr1 = t1 instanceof IPointerType;
if (isPtr1 || isNullPtr(t1)) {
if (isNullPointerConstant(t2)) {
return t1;
}
}
final boolean isPtr2 = t2 instanceof IPointerType;
if (isPtr2 || isNullPtr(t2)) {
if (isNullPointerConstant(t1)) {
return t2;
}
}
if (!isPtr1 || !isPtr2)
return null;
final IPointerType p1= (IPointerType) t1;
final IPointerType p2= (IPointerType) t2;
if (haveMemberPtrConflict(p1, p2))
return null;
final IType target1 = p1.getType();
if (isVoidType(target1)) {
return addQualifiers(p1, p2.isConst(), p2.isVolatile(), p2.isRestrict());
}
final IType target2 = p2.getType();
if (isVoidType(target2)) {
return addQualifiers(p2, p1.isConst(), p1.isVolatile(), p1.isRestrict());
}
IType t= mergePointers(target1, target2, true, true);
if (t == null)
return null;
if (t == target1)
return p1;
if (t == target2)
return p2;
return copyPointer(p1, t, false, false);
}
private static IType mergePointers(IType t1, IType t2, boolean allcq, boolean allowInheritance) {
t1= getNestedType(t1, TDEF | REF);
t2= getNestedType(t2, TDEF | REF);
if (t1 instanceof IPointerType && t2 instanceof IPointerType) {
final IPointerType p1 = (IPointerType) t1;
final IPointerType p2 = (IPointerType) t2;
final CVQualifier cv1= getCVQualifier(t1);
final CVQualifier cv2= getCVQualifier(t2);
if (haveMemberPtrConflict(p1, p2))
return null;
if (!allcq && cv1 != cv2)
return null;
final IType p1target = p1.getType();
IType merged= mergePointers(p1target, p2.getType(), allcq && (cv1.isConst() || cv2.isConst()), false);
if (merged == null)
return null;
if (p1target == merged && cv1.isAtLeastAsQualifiedAs(cv2))
return p1;
if (p2.getType() == merged && cv2.isAtLeastAsQualifiedAs(cv1))
return p2;
return copyPointer(p1, merged, cv1.isConst() || cv2.isConst(), cv1.isVolatile() || cv2.isVolatile());
}
final IType uq1= getNestedType(t1, TDEF|REF|CVTYPE);
final IType uq2= getNestedType(t2, TDEF|REF|CVTYPE);
if (uq1 == null) {
return null;
}
if (uq1.isSameType(uq2)) {
if (uq1 == t1 && uq2 == t2)
return t1;
CVQualifier cv1= getCVQualifier(t1);
CVQualifier cv2= getCVQualifier(t2);
if (cv1 == cv2)
return t1;
if (!allcq)
return null;
if (cv1.isAtLeastAsQualifiedAs(cv2))
return t1;
if (cv2.isAtLeastAsQualifiedAs(cv1))
return t2;
// One type is const the other is volatile.
return new CPPQualifierType(uq1, true, true);
} else if (allowInheritance) {
// Allow for conversion from pointer-to-derived to pointer-to-base as per [conv.ptr] p3.
IType base;
if (SemanticUtil.calculateInheritanceDepth(uq1, uq2) > 0) {
base = uq2;
} else if (SemanticUtil.calculateInheritanceDepth(uq2, uq1) > 0) {
base = uq1;
} else {
return null;
}
CVQualifier cv1= getCVQualifier(t1);
CVQualifier cv2= getCVQualifier(t2);
if (cv1 == CVQualifier.NONE && cv2 == CVQualifier.NONE) {
return base;
}
return new CPPQualifierType(base, cv1.isConst() || cv2.isConst(), cv1.isVolatile() || cv2.isVolatile());
}
return null;
}
public static IType copyPointer(final IPointerType p1, IType target, final boolean isConst,
final boolean isVolatile) {
if (p1 instanceof ICPPPointerToMemberType) {
ICPPPointerToMemberType ptm= (ICPPPointerToMemberType) p1;
return new CPPPointerToMemberType(target, ptm.getMemberOfClass(), isConst, isVolatile, false);
}
return new CPPPointerType(target, isConst, isVolatile, false);
}
private static boolean isNullPtr(IType t1) {
return t1 instanceof IBasicType && ((IBasicType) t1).getKind() == Kind.eNullPtr;
}
}