1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-07-23 17:05:26 +02:00

Bug 324096: Use value categories in overload resolution.

This commit is contained in:
Markus Schorn 2010-09-08 09:35:41 +00:00
parent 4f83e760c3
commit f8a5d13356
11 changed files with 303 additions and 225 deletions

View file

@ -42,6 +42,7 @@ import org.eclipse.cdt.core.dom.ast.IASTFunctionCallExpression;
import org.eclipse.cdt.core.dom.ast.IASTFunctionDeclarator;
import org.eclipse.cdt.core.dom.ast.IASTFunctionDefinition;
import org.eclipse.cdt.core.dom.ast.IASTIdExpression;
import org.eclipse.cdt.core.dom.ast.IASTImplicitName;
import org.eclipse.cdt.core.dom.ast.IASTImplicitNameOwner;
import org.eclipse.cdt.core.dom.ast.IASTLabelStatement;
import org.eclipse.cdt.core.dom.ast.IASTLiteralExpression;
@ -8915,4 +8916,25 @@ public class AST2CPPTests extends AST2BaseTest {
bh.assertProblem("fint(pe + pe);", 4);
bh.assertNonProblem("fint(p + p);", 4);
}
// struct C {
// C(const C& c) {}
// };
// struct D {
// explicit operator C();
// };
// void f() {
// D d;
// C c (d);
// }
public void testExplicitOperatorInDirectInit() throws Exception {
String code= getAboveComment();
IASTTranslationUnit tu= parseAndCheckBindings(code);
ICPPASTFunctionDefinition fdef= getDeclaration(tu, 2);
IASTDeclarationStatement declstmt= getStatement(fdef, 1);
IASTSimpleDeclaration decl= (IASTSimpleDeclaration) declstmt.getDeclaration();
IASTImplicitName[] names = ((IASTImplicitNameOwner) decl.getDeclarators()[0]).getImplicitNames();
assertEquals(1, names.length);
assertTrue(names[0].resolveBinding() instanceof ICPPConstructor);
}
}

View file

@ -134,7 +134,7 @@ public class CPPASTConditionalExpression extends ASTNode implements IASTConditio
}
}
// mstodo type of conditional operator
// mstodo conditional operator (type)
public IType getExpressionType() {
IASTExpression positiveExpression = getPositiveResultExpression();
if (positiveExpression == null) {
@ -147,7 +147,7 @@ public class CPPASTConditionalExpression extends ASTNode implements IASTConditio
return t2;
}
// mstodo
// mstodo conditional operator (value category)
public ValueCategory getValueCategory() {
return PRVALUE;
}

View file

@ -15,10 +15,11 @@
*******************************************************************************/
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.core.dom.ast.IASTExpression.ValueCategory.PRVALUE;
import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.*;
import java.util.ArrayList;
import java.util.BitSet;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
@ -44,6 +45,7 @@ import org.eclipse.cdt.core.dom.ast.IASTElaboratedTypeSpecifier;
import org.eclipse.cdt.core.dom.ast.IASTEnumerationSpecifier.IASTEnumerator;
import org.eclipse.cdt.core.dom.ast.IASTEqualsInitializer;
import org.eclipse.cdt.core.dom.ast.IASTExpression;
import org.eclipse.cdt.core.dom.ast.IASTExpression.ValueCategory;
import org.eclipse.cdt.core.dom.ast.IASTFieldReference;
import org.eclipse.cdt.core.dom.ast.IASTFunctionCallExpression;
import org.eclipse.cdt.core.dom.ast.IASTFunctionDeclarator;
@ -131,6 +133,7 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPNamespace;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPNamespaceScope;
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.ICPPScope;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPSpecialization;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateArgument;
@ -193,6 +196,7 @@ import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPInternalNamespaceScope;
import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPUnknownBinding;
import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPUnknownType;
import org.eclipse.cdt.internal.core.dom.parser.cpp.OverloadableOperator;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.Conversions.Context;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.Conversions.UDCMode;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.Cost.Rank;
import org.eclipse.cdt.internal.core.index.IIndexScope;
@ -2288,7 +2292,7 @@ public class CPPSemantics {
}
if (!isFuncDecl || data.forExplicitFunctionSpecialization()) {
CPPTemplates.instantiateFunctionTemplates(fns, data.getFunctionArgumentTypes(), data.getFunctionArgumentLValues(),
CPPTemplates.instantiateFunctionTemplates(fns, data.getFunctionArgumentTypes(), data.getFunctionArgumentValueCategories(),
data.astName, data.argsContainImpliedObject);
}
@ -2386,7 +2390,7 @@ public class CPPSemantics {
private static FunctionCost costForFunctionCall(IFunction fn, boolean allowUDC, LookupData data)
throws DOMException {
IType[] argTypes = data.getFunctionArgumentTypes();
BitSet isLValue= data.getFunctionArgumentLValues();
ValueCategory[] isLValue= data.getFunctionArgumentValueCategories();
int skipArg= 0;
final ICPPFunctionType ftype= (ICPPFunctionType) fn.getType();
if (ftype == null)
@ -2412,7 +2416,7 @@ public class CPPSemantics {
} else {
result= new FunctionCost(fn, sourceLen + 1);
boolean sourceIsLValue= true;
ValueCategory sourceIsLValue= LVALUE;
if (impliedObjectType == null) {
impliedObjectType= data.getImpliedObjectType();
}
@ -2425,7 +2429,7 @@ public class CPPSemantics {
} else if (impliedObjectType.isSameType(implicitParameterType)) {
cost = new Cost(impliedObjectType, implicitParameterType, Rank.IDENTITY);
} else {
cost = Conversions.checkImplicitConversionSequence(implicitParameterType, impliedObjectType, sourceIsLValue, UDCMode.noUDC, true);
cost = Conversions.checkImplicitConversionSequence(implicitParameterType, impliedObjectType, sourceIsLValue, UDCMode.FORBIDDEN, Context.IMPLICIT_OBJECT);
if (!cost.converts()) {
if (CPPTemplates.isDependentType(implicitParameterType) || CPPTemplates.isDependentType(impliedObjectType)) {
IType s= getNestedType(impliedObjectType, TDEF|REF|CVTYPE);
@ -2443,17 +2447,17 @@ public class CPPSemantics {
result.setCost(k++, cost, sourceIsLValue);
}
final UDCMode udc = allowUDC ? UDCMode.deferUDC : UDCMode.noUDC;
final UDCMode udc = allowUDC ? UDCMode.DEFER : UDCMode.FORBIDDEN;
for (int j = 0; j < sourceLen; j++) {
final IType argType= SemanticUtil.getNestedType(argTypes[j+skipArg], TDEF | REF);
if (argType == null)
return null;
final boolean sourceIsLValue = isLValue.get(j+skipArg);
final ValueCategory sourceIsLValue = isLValue[j+skipArg];
IType paramType;
if (j < paramTypes.length) {
paramType= paramTypes[j];
paramType= getNestedType(paramTypes[j], TDEF);
} else if (!fn.takesVarArgs()) {
paramType= VOID_TYPE;
} else {
@ -2467,7 +2471,16 @@ public class CPPSemantics {
} else {
if (CPPTemplates.isDependentType(paramType))
return CONTAINS_DEPENDENT_TYPES;
cost = Conversions.checkImplicitConversionSequence(paramType, argType, sourceIsLValue, udc, false);
Context ctx= Context.ORDINARY;
if (j==0 && sourceLen == 1 && fn instanceof ICPPConstructor) {
if (paramType instanceof ICPPReferenceType && !((ICPPReferenceType) paramType).isRValueReference()) {
if (((ICPPConstructor) fn).getClassOwner().isSameType(getNestedType(paramType, TDEF|REF|CVTYPE))) {
ctx= Context.FIRST_PARAM_OF_DIRECT_COPY_CTOR;
}
}
}
cost = Conversions.checkImplicitConversionSequence(paramType, argType, sourceIsLValue, udc, ctx);
if (data.fNoNarrowing && cost.isNarrowingConversion()) {
cost= Cost.NO_CONVERSION;
}
@ -2941,22 +2954,23 @@ public class CPPSemantics {
type = SemanticUtil.getNestedType(((ICPPVariable) binding).getType(), TDEF | CVTYPE);
if (!(type instanceof ICPPClassType))
return null;
final ICPPClassType classType = (ICPPClassType) type;
// Copy initialization
if (initializer instanceof IASTEqualsInitializer) {
IASTEqualsInitializer eqInit= (IASTEqualsInitializer) initializer;
IASTInitializerClause initClause = eqInit.getInitializerClause();
IType sourceType= null;
boolean isLValue= false;
ValueCategory isLValue= PRVALUE;
if (initClause instanceof IASTExpression) {
final IASTExpression expr = (IASTExpression) initClause;
isLValue= expr.isLValue();
isLValue= expr.getValueCategory();
sourceType= SemanticUtil.getSimplifiedType(expr.getExpressionType());
} else if (initClause instanceof ICPPASTInitializerList) {
sourceType= new InitializerListType((ICPPASTInitializerList) initClause);
}
if (sourceType != null) {
Cost c= Conversions.checkUserDefinedConversionSequence(isLValue, sourceType, type, false, false);
Cost c= Conversions.copyInitializationOfClass(isLValue, sourceType, classType, false);
if (c.converts()) {
IFunction f= c.getUserDefinedConversion();
if (f instanceof ICPPConstructor)
@ -2967,7 +2981,6 @@ public class CPPSemantics {
}
// Direct Initialization
ICPPClassType classType = (ICPPClassType) type;
CPPASTName astName = new CPPASTName();
astName.setName(classType.getNameCharArray());
astName.setOffsetAndLength((ASTNode) name);
@ -3022,9 +3035,6 @@ public class CPPSemantics {
return null;
}
/**
* mstodo remove
*/
public static IASTExpression createArgForType(IASTNode node, IType type) {
CPPASTName x= new CPPASTName();
x.setBinding(createVariable(x, type, false, false));

View file

@ -13,8 +13,9 @@
*******************************************************************************/
package org.eclipse.cdt.internal.core.dom.parser.cpp.semantics;
import static org.eclipse.cdt.core.dom.ast.IASTExpression.ValueCategory.LVALUE;
import java.util.ArrayList;
import java.util.BitSet;
import java.util.Collections;
import java.util.List;
@ -28,6 +29,7 @@ import org.eclipse.cdt.core.dom.ast.IASTDeclaration;
import org.eclipse.cdt.core.dom.ast.IASTDeclarator;
import org.eclipse.cdt.core.dom.ast.IASTElaboratedTypeSpecifier;
import org.eclipse.cdt.core.dom.ast.IASTExpression;
import org.eclipse.cdt.core.dom.ast.IASTExpression.ValueCategory;
import org.eclipse.cdt.core.dom.ast.IASTFunctionDefinition;
import org.eclipse.cdt.core.dom.ast.IASTIdExpression;
import org.eclipse.cdt.core.dom.ast.IASTInitializerClause;
@ -139,6 +141,7 @@ import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPUnknownBinding;
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.ICPPUnknownType;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.Conversions.Context;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.Conversions.UDCMode;
/**
@ -146,7 +149,6 @@ import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.Conversions.UDCMod
* type instantiation.
*/
public class CPPTemplates {
private static final BitSet ALL_RVALUES = new BitSet();
private static final int PACK_SIZE_DEFER = -1;
private static final int PACK_SIZE_FAIL = -2;
private static final int PACK_SIZE_NOT_FOUND = Integer.MAX_VALUE;
@ -1539,7 +1541,7 @@ public class CPPTemplates {
}
static protected void instantiateFunctionTemplates(IFunction[] functions, IType[] allFnArgs,
BitSet allArgIsLValue, IASTName name, boolean argsContainImpliedObject) {
ValueCategory[] allValueCategories, IASTName name, boolean argsContainImpliedObject) {
boolean requireTemplate= false;
if (name != null) {
if (name.getPropertyInParent() == ICPPASTTemplateId.TEMPLATE_NAME) {
@ -1551,7 +1553,7 @@ public class CPPTemplates {
}
IType[] reducedFnArgs= null;
BitSet reducedIsLValue= null;
ValueCategory[] reducedValueCategories= null;
ICPPTemplateArgument[] tmplArgs= null;
for (int i = 0; i < functions.length; i++) {
IFunction func = functions[i];
@ -1560,23 +1562,23 @@ public class CPPTemplates {
functions[i]= null;
final IType[] fnArgs;
final BitSet argIsLValue;
final ValueCategory[] valueCategories;
if (argsContainImpliedObject && template instanceof ICPPMethod) {
if (reducedIsLValue == null) {
if (reducedValueCategories == null) {
if (allFnArgs != null && allFnArgs.length > 0) {
reducedFnArgs= ArrayUtil.removeFirst(allFnArgs);
}
if (allArgIsLValue == null || allArgIsLValue.length() == 0) {
reducedIsLValue= ALL_RVALUES;
if (allValueCategories == null || allValueCategories.length == 0) {
reducedValueCategories= new ValueCategory[0];
} else {
reducedIsLValue= allArgIsLValue.get(1, allArgIsLValue.length());
reducedValueCategories= ArrayUtil.removeFirst(allValueCategories);
}
}
fnArgs= reducedFnArgs;
argIsLValue= reducedIsLValue;
valueCategories= reducedValueCategories;
} else {
fnArgs= allFnArgs;
argIsLValue= allArgIsLValue;
valueCategories= allValueCategories;
}
// extract template arguments and parameter types.
@ -1600,7 +1602,7 @@ public class CPPTemplates {
}
CPPTemplateParameterMap map= new CPPTemplateParameterMap(fnArgs.length);
try {
ICPPTemplateArgument[] args= TemplateArgumentDeduction.deduceForFunctionCall(template, tmplArgs, fnArgs, argIsLValue, map);
ICPPTemplateArgument[] args= TemplateArgumentDeduction.deduceForFunctionCall(template, tmplArgs, fnArgs, valueCategories, map);
if (args != null) {
IBinding instance= instantiateFunctionTemplate(template, args, map);
if (instance instanceof IFunction) {
@ -1719,7 +1721,7 @@ public class CPPTemplates {
map= new CPPTemplateParameterMap(2);
final IType[] transferredParameterTypes = ((ICPPFunction) transferredTemplate).getType().getParameterTypes();
if (!TemplateArgumentDeduction.deduceFromFunctionArgs(f2, transferredParameterTypes, ALL_RVALUES, map, true))
if (!TemplateArgumentDeduction.deduceFromFunctionArgs(f2, transferredParameterTypes, null, map, true))
return false;
final int last = tmplParams1.length -1;
@ -1981,7 +1983,7 @@ public class CPPTemplates {
} else if (paramType instanceof IArrayType) {
paramType = new CPPPointerType(((IArrayType) paramType).getType());
}
Cost cost = Conversions.checkImplicitConversionSequence(paramType, arg, true, UDCMode.noUDC, false);
Cost cost = Conversions.checkImplicitConversionSequence(paramType, arg, LVALUE, UDCMode.FORBIDDEN, Context.ORDINARY);
return cost != null && cost.converts();
}

View file

@ -16,7 +16,6 @@ package org.eclipse.cdt.internal.core.dom.parser.cpp.semantics;
import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.*;
import java.util.ArrayList;
import java.util.BitSet;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
@ -40,6 +39,7 @@ import org.eclipse.cdt.core.dom.ast.IASTEnumerationSpecifier;
import org.eclipse.cdt.core.dom.ast.IASTEnumerationSpecifier.IASTEnumerator;
import org.eclipse.cdt.core.dom.ast.IASTEqualsInitializer;
import org.eclipse.cdt.core.dom.ast.IASTExpression;
import org.eclipse.cdt.core.dom.ast.IASTExpression.ValueCategory;
import org.eclipse.cdt.core.dom.ast.IASTFieldReference;
import org.eclipse.cdt.core.dom.ast.IASTForStatement;
import org.eclipse.cdt.core.dom.ast.IASTFunctionCallExpression;
@ -1791,6 +1791,7 @@ public class CPPVisitor extends ASTQueries {
IType type = AutoTypeResolver.AUTO_TYPE;
IType initType = null;
ValueCategory valueCat= null;
ICPPClassTemplate initializer_list_template = null;
try {
if (initClause instanceof ICPPASTInitializerList) {
@ -1804,7 +1805,9 @@ public class CPPVisitor extends ASTQueries {
type = decorateType(type, declSpec, declarator);
if (initClause instanceof IASTExpression) {
initType = ((IASTExpression) initClause).getExpressionType();
final IASTExpression expression = (IASTExpression) initClause;
initType = expression.getExpressionType();
valueCat= expression.getValueCategory();
} else if (initClause instanceof ICPPASTInitializerList) {
initType = new InitializerListType((ICPPASTInitializerList) initClause);
}
@ -1816,8 +1819,8 @@ public class CPPVisitor extends ASTQueries {
}
ICPPFunctionTemplate template = new AutoTypeResolver(type);
CPPTemplateParameterMap paramMap = new CPPTemplateParameterMap(1);
TemplateArgumentDeduction.deduceFromFunctionArgs(template, new IType[] { initType }, new BitSet(),
paramMap, false);
TemplateArgumentDeduction.deduceFromFunctionArgs(template, new IType[] { initType },
new ValueCategory[] { valueCat }, paramMap, false);
ICPPTemplateArgument argument = paramMap.getArgument(0, 0);
if (argument == null) {
return null;

View file

@ -14,13 +14,14 @@
*******************************************************************************/
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.CVQualifier._;
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.*;
import java.util.BitSet;
import org.eclipse.cdt.core.dom.ast.DOMException;
import org.eclipse.cdt.core.dom.ast.IASTExpression;
import org.eclipse.cdt.core.dom.ast.IASTExpression.ValueCategory;
import org.eclipse.cdt.core.dom.ast.IASTInitializerClause;
import org.eclipse.cdt.core.dom.ast.IASTLiteralExpression;
import org.eclipse.cdt.core.dom.ast.IASTName;
@ -55,6 +56,7 @@ 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.ClassTypeHelper;
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;
@ -62,30 +64,26 @@ import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.Cost.ReferenceBind
* Routines for calculating the cost of conversions.
*/
public class Conversions {
enum UDCMode {allowUDC, noUDC, deferUDC}
enum UDCMode {ALLOWED, FORBIDDEN, DEFER}
enum Context {ORDINARY, IMPLICIT_OBJECT, FIRST_PARAM_OF_DIRECT_COPY_CTOR}
private static final BitSet RVBITSET = new BitSet();
private static final BitSet LVBITSET = new BitSet();
static {
LVBITSET.set(0, true);
}
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
* 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 exprIsLValue whether the source type is an lvalue
* @param isImpliedObjectType
* @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,
boolean exprIsLValue, UDCMode udc, boolean isImpliedObjectType) throws DOMException {
if (isImpliedObjectType) {
udc= UDCMode.noUDC;
ValueCategory valueCat, UDCMode udc, Context ctx) throws DOMException {
final boolean isImpliedObject= ctx == Context.IMPLICIT_OBJECT;
if (isImpliedObject) {
udc= UDCMode.FORBIDDEN;
}
target= getNestedType(target, TDEF);
@ -99,12 +97,13 @@ public class Conversions {
final IType cv2T2= exprType;
final IType T2= getNestedType(cv2T2, TDEF | REF | ALLCVQ);
final boolean isImplicitWithoutRefQualifier = isImpliedObjectType;
// mstodo: will change when implementing rvalue references on this pointer
final boolean isImplicitWithoutRefQualifier = isImpliedObject;
ReferenceBinding refBindingType= ReferenceBinding.OTHER;
if (!isImplicitWithoutRefQualifier) {
if (isLValueRef) {
refBindingType= ReferenceBinding.LVALUE_REF;
} else if (exprIsLValue) {
} else if (valueCat == LVALUE) {
refBindingType= ReferenceBinding.RVALUE_REF_BINDS_RVALUE;
}
}
@ -113,9 +112,9 @@ public class Conversions {
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 (exprIsLValue) {
if (valueCat == LVALUE) {
// ... and "cv1 T1" is reference-compatible with "cv2 T2"
Cost cost= isReferenceCompatible(cv1T1, cv2T2, isImpliedObjectType);
Cost cost= isReferenceCompatible(cv1T1, cv2T2, isImpliedObject);
if (cost != null) {
// [13.3.3.1.4-1] direct binding has either identity or conversion rank.
if (cost.getInheritanceDistance() > 0) {
@ -129,8 +128,8 @@ public class Conversions {
// 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.noUDC && isReferenceRelated(T1, T2) < 0) {
Cost cost= conversionFuncForDirectReference(cv1T1, cv2T2, T2, true);
if (T2 instanceof ICPPClassType && udc != UDCMode.FORBIDDEN && isReferenceRelated(T1, T2) < 0) {
Cost cost= initializationByConversionForDirectReference(cv1T1, cv2T2, (ICPPClassType) T2, true, ctx);
if (cost != null) {
cost.setReferenceBinding(refBindingType);
return cost;
@ -140,22 +139,46 @@ public class Conversions {
// 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 and the initializer expression
// shall be an rvalue.
// shall be an rvalue or have function type.
boolean ok;
if (isLValueRef) {
ok = getCVQualifier(cv1T1) == CVQualifier.c;
} else {
ok= !exprIsLValue;
ok= valueCat.isRValue() || T2 instanceof IFunctionType;
}
if (!ok) {
return Cost.NO_CONVERSION;
}
// If T1 and T2 are class types and ...
if (T1 instanceof ICPPClassType && T2 instanceof ICPPClassType) {
// ... the initializer expression is an rvalue and cv1 T1 is reference-compatible with cv2 T2
if (!exprIsLValue) {
Cost cost= isReferenceCompatible(cv1T1, cv2T2, isImpliedObjectType);
// If T1 is a function type, then
if (T1 instanceof IFunctionType) {
// if T2 is the same type as T1, the reference is bound to the initializer expression lvalue;
if (T2.isSameType(T1)) {
Cost cost= new Cost(T1, T2, Rank.IDENTITY);
cost.setReferenceBinding(refBindingType);
return cost;
}
// if T2 is a class type and the initializer expression can be implicitly converted to an lvalue of
// type T1 (this conversion is selected by enumerating the applicable conversion functions (13.3.1.6)
// and choosing the best one through overload resolution (13.3)), the reference is bound to the
// function lvalue that is the result of the conversion;
if (T2 instanceof ICPPClassType) {
Cost cost= initializationByConversionForDirectReference(cv1T1, cv2T2, (ICPPClassType) T2, true, ctx);
if (cost != null) {
cost.setReferenceBinding(refBindingType);
return cost;
}
}
// otherwise, the program is ill-formed.
return Cost.NO_CONVERSION;
}
// Otherwise, if T2 is a class type and
if (T2 instanceof ICPPClassType) {
// ... the initializer expression is an rvalue and 'cv1 T1' is reference-compatible with 'cv2 T2'
// ..., then the reference is bound to the initializer expression rvalue in the first case
if (valueCat.isRValue()) {
Cost cost= isReferenceCompatible(cv1T1, cv2T2, isImpliedObject);
if (cost != null) {
// [13.3.3.1.4-1] direct binding has either identity or conversion rank.
if (cost.getInheritanceDistance() > 0) {
@ -167,13 +190,13 @@ public class Conversions {
}
// or T1 is not reference-related to T2 and the initializer expression can be implicitly
// converted to an rvalue of type cv3 T3 (this conversion is selected by enumerating the
// converted to an rvalue of type '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)), then the reference is bound to the initializer expression rvalue in the
// first case and to the object that is the result of the conversion in the second case (or,
// in either case, to the appropriate base class subobject of the object).
if (udc != UDCMode.noUDC && isReferenceRelated(T1, T2) < 0) {
Cost cost= conversionFuncForDirectReference(cv1T1, cv2T2, T2, false);
// in either case, to the appropriate base class sub-object of the object).
if (udc != UDCMode.FORBIDDEN && isReferenceRelated(T1, T2) < 0) {
Cost cost= initializationByConversionForDirectReference(cv1T1, cv2T2, (ICPPClassType) T2, false, ctx);
if (cost != null) {
cost.setReferenceBinding(refBindingType);
return cost;
@ -181,11 +204,11 @@ public class Conversions {
}
}
// If the initializer expression is an rvalue, with T2 an array type, and cv1 T1 is
// reference-compatible with cv2 T2, the reference is bound to the object represented by the
// If the initializer expression is an rvalue, with T2 an array type, and 'cv1 T1' is
// reference-compatible with 'cv2 T2' the reference is bound to the object represented by the
// rvalue (see 3.10).
if (!exprIsLValue && T2 instanceof IArrayType) {
Cost cost= isReferenceCompatible(cv1T1, cv2T2, isImpliedObjectType);
if (T2 instanceof IArrayType && valueCat.isRValue()) {
Cost cost= isReferenceCompatible(cv1T1, cv2T2, isImpliedObject);
if (cost != null) {
cost.setReferenceBinding(refBindingType);
return cost;
@ -198,9 +221,9 @@ public class Conversions {
// as, or greater cv-qualification than, cv2; otherwise, the program is ill-formed.
// 13.3.3.1.7 no temporary object when converting the implicit object parameter
if (!isImpliedObjectType) {
if (!isImpliedObject) {
if (isReferenceRelated(T1, T2) < 0 || compareQualifications(cv1T1, cv2T2) >= 0) {
Cost cost= nonReferenceConversion(exprIsLValue, cv2T2, T1, udc, false);
Cost cost= nonReferenceConversion(valueCat, cv2T2, T1, udc, false);
if (!isImplicitWithoutRefQualifier && cost.converts()) {
cost.setReferenceBinding(isLValueRef ? ReferenceBinding.LVALUE_REF : ReferenceBinding.RVALUE_REF_BINDS_RVALUE);
}
@ -227,31 +250,36 @@ public class Conversions {
}
}
return nonReferenceConversion(exprIsLValue, exprType, uqtarget, udc, isImpliedObjectType);
return nonReferenceConversion(valueCat, exprType, uqtarget, udc, isImpliedObject);
}
/**
* C++0x: 13.3.1.6 Initialization by conversion function for direct reference binding
*/
private static Cost conversionFuncForDirectReference(final IType cv1T1, final IType cv2T2, final IType T2, boolean forLValue)
private static Cost initializationByConversionForDirectReference(final IType cv1T1, final IType cv2T2, final ICPPClassType T2, boolean needLValue, Context ctx)
throws DOMException {
ICPPMethod[] fcns= SemanticUtil.getConversionOperators((ICPPClassType) T2);
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 convertedType= ft.getReturnType();
final boolean isLValue = CPPVisitor.isLValueReference(convertedType);
if (isLValue == forLValue) { // require an lvalue or rvalue
IType implicitObjectType= CPPSemantics.getImplicitParameterType(op, ft.isConst(), ft.isVolatile());
Cost udcCost= isReferenceCompatible(getNestedType(implicitObjectType, TDEF | REF), cv2T2, true); // expression type to implicit object type
IType t= getNestedType(ft.getReturnType(), TDEF);
final boolean isLValueRef= t instanceof ICPPReferenceType && !((ICPPReferenceType) t).isRValueReference();
if (isLValueRef == needLValue) { // require an lvalue or rvalue
IType implicitParameterType= CPPSemantics.getImplicitParameterType(op, ft.isConst(), ft.isVolatile());
Cost udcCost= isReferenceCompatible(getNestedType(implicitParameterType, TDEF | REF), cv2T2, true); // expression type to implicit object type
if (udcCost != null) {
FunctionCost udcFuncCost= new FunctionCost(op, udcCost);
int cmp= udcFuncCost.compareTo(null, bestUdcCost);
if (cmp <= 0) {
Cost cost= isReferenceCompatible(cv1T1, getNestedType(convertedType, TDEF | REF), false); // converted to target
Cost cost= isReferenceCompatible(cv1T1, getNestedType(t, TDEF | REF), false); // converted to target
if (cost != null) {
bestUdcCost= udcFuncCost;
ambiguousConversionOperator= cmp == 0;
@ -270,18 +298,43 @@ public class Conversions {
return null;
}
private static Cost nonReferenceConversion(boolean sourceIsLValue, IType source, IType target, UDCMode udc, boolean isImpliedObject) throws DOMException {
// mstodo fix this to better match the specification
/**
* 8.5-16
*/
private static Cost nonReferenceConversion(ValueCategory valueCat, IType source, IType target, UDCMode udc, boolean isImpliedObject) throws DOMException {
if (source instanceof InitializerListType) {
return listInitializationSequence(((InitializerListType) source), target, udc, false);
}
// [13.3.3.1-6] Subsume cv-qualifications
IType uqSource= SemanticUtil.getNestedType(source, TDEF | ALLCVQ);
Cost cost= checkStandardConversionSequence(uqSource, sourceIsLValue, target, isImpliedObject);
if (cost.converts() || udc == UDCMode.noUDC)
return cost;
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(uqTarget, uqSource);
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);
}
return checkUserDefinedConversionSequence(sourceIsLValue, source, target, udc == UDCMode.deferUDC, false);
if (uqSource instanceof ICPPClassType) {
if (udc == UDCMode.FORBIDDEN)
return Cost.NO_CONVERSION;
return initializationByConversion(valueCat, source, (ICPPClassType) uqSource, target, udc == UDCMode.DEFER);
}
return checkStandardConversionSequence(uqSource, target, isImpliedObject);
}
/**
@ -291,11 +344,11 @@ public class Conversions {
IType listType= getInitListType(target);
if (listType != null) {
IType[] exprTypes= arg.getExpressionTypes();
BitSet isLValue= arg.getIsLValue();
ValueCategory[] valueCats= arg.getValueCategories();
Cost worstCost= new Cost(arg, target, Rank.IDENTITY);
for (int i = 0; i < exprTypes.length; i++) {
IType exprType = exprTypes[i];
Cost cost= checkImplicitConversionSequence(listType, exprType, isLValue.get(i), UDCMode.allowUDC, false);
Cost cost= checkImplicitConversionSequence(listType, exprType, valueCats[i], UDCMode.ALLOWED, Context.ORDINARY);
if (!cost.converts())
return cost;
if (cost.isNarrowingConversion()) {
@ -311,7 +364,7 @@ public class Conversions {
IType noCVTarget= getNestedType(target, CVTYPE | TDEF);
if (noCVTarget instanceof ICPPClassType) {
if (udc == UDCMode.noUDC)
if (udc == UDCMode.FORBIDDEN)
return Cost.NO_CONVERSION;
ICPPClassType classTarget= (ICPPClassType) noCVTarget;
@ -320,7 +373,7 @@ public class Conversions {
cost.setUserDefinedConversion(null);
return cost;
}
return checkUserDefinedConversionSequence(false, arg, target, udc == UDCMode.deferUDC, isDirect);
return listInitializationOfClass(arg, classTarget, isDirect, udc == UDCMode.DEFER);
}
IASTInitializerClause[] args = arg.getInitializerList().getClauses();
@ -328,7 +381,7 @@ public class Conversions {
final IASTInitializerClause firstArg = args[0];
if (firstArg instanceof IASTExpression) {
IASTExpression expr= (IASTExpression) firstArg;
Cost cost= checkImplicitConversionSequence(target, expr.getExpressionType(), expr.isLValue(), udc, false);
Cost cost= checkImplicitConversionSequence(target, expr.getExpressionType(), expr.getValueCategory(), udc, Context.ORDINARY);
if (cost.isNarrowingConversion()) {
return Cost.NO_CONVERSION;
}
@ -484,10 +537,9 @@ public class Conversions {
* classes are nominated via using-declarations. In such a situation the derived to
* base conversion does not cause any costs.
*/
private static final Cost checkStandardConversionSequence(IType source, boolean isLValue, IType target,
boolean isImplicitThis) {
private static final Cost checkStandardConversionSequence(IType source, IType target, boolean isImplicitThis) {
final Cost cost= new Cost(source, target, Rank.IDENTITY);
if (lvalue_to_rvalue(cost, isLValue))
if (lvalue_to_rvalue(cost))
return cost;
if (promotion(cost))
@ -504,40 +556,14 @@ public class Conversions {
return cost;
}
/**
* [13.3.3.1.2] User-defined conversions
*/
static final Cost checkUserDefinedConversionSequence(boolean sourceIsLValue, IType source, IType target, boolean deferUDC, boolean isDirect) throws DOMException {
IType s= getNestedType(source, TDEF | CVTYPE | REF);
IType t= getNestedType(target, TDEF | CVTYPE | REF);
if (!(s instanceof ICPPClassType || t instanceof ICPPClassType)) {
return Cost.NO_CONVERSION;
}
// 13.3.1.7 Initialization by list-initialization
static Cost listInitializationOfClass(InitializerListType arg, ICPPClassType t, boolean isDirect, boolean deferUDC) throws DOMException {
if (deferUDC) {
Cost c= new Cost(source, target, Rank.USER_DEFINED_CONVERSION);
c.setDeferredUDC(true);
Cost c= new Cost(arg, t, Rank.USER_DEFINED_CONVERSION);
c.setDeferredUDC(isDirect ? DeferredUDC.DIRECT_LIST_INIT_OF_CLASS : DeferredUDC.LIST_INIT_OF_CLASS);
return c;
}
if (t instanceof ICPPClassType) {
if (s instanceof InitializerListType) {
// 13.3.1.7 Initialization by list-initialization
return listInitializationOfClass((InitializerListType) s, (ICPPClassType) t, isDirect);
}
// 13.3.1.4 Copy initialization of class by user-defined conversion
return copyInitalizationOfClass(sourceIsLValue, source, s, target, (ICPPClassType) t);
}
if (s instanceof ICPPClassType) {
// 13.3.1.5 Initialization by conversion function
return initializationByConversion(source, (ICPPClassType) s, target, isDirect);
}
return Cost.NO_CONVERSION;
}
private static Cost listInitializationOfClass(InitializerListType arg, ICPPClassType t, boolean isDirect) throws DOMException {
// If T has an initializer-list constructor
ICPPConstructor usedCtor= null;
Cost bestCost= null;
@ -551,7 +577,7 @@ public class Conversions {
final IType target = parTypes[0];
if (getInitListType(target) != null) {
hasInitListConstructor= true;
Cost cost= listInitializationSequence(arg, target, UDCMode.noUDC, isDirect);
Cost cost= listInitializationSequence(arg, target, UDCMode.FORBIDDEN, isDirect);
if (cost.converts()) {
int cmp= cost.compareTo(bestCost);
if (bestCost == null || cmp < 0) {
@ -624,14 +650,22 @@ public class Conversions {
/**
* 13.3.1.4 Copy-initialization of class by user-defined conversion [over.match.copy]
*/
private static Cost copyInitalizationOfClass(boolean sourceIsLValue, IType source, IType s, IType target,
ICPPClassType t) throws DOMException {
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;
ICPPConstructor[] ctors= t.getConstructors();
CPPTemplates.instantiateFunctionTemplates(ctors, new IType[]{source}, sourceIsLValue ? LVBITSET : RVBITSET, null, false);
CPPTemplates.instantiateFunctionTemplates(ctors, new IType[]{source}, new ValueCategory[] {valueCat}, null, false);
for (ICPPConstructor ctor : ctors) {
// 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 != null && !(ctor instanceof IProblemBinding) && !ctor.isExplicit()) {
final ICPPFunctionType ft = ctor.getType();
final IType[] ptypes = ft.getParameterTypes();
@ -650,7 +684,7 @@ public class Conversions {
if (ctor.getRequiredArgumentCount() > 1)
continue;
c1= new FunctionCost(ctor, checkImplicitConversionSequence(ptype, source, sourceIsLValue, UDCMode.noUDC, false));
c1= new FunctionCost(ctor, checkImplicitConversionSequence(ptype, source, valueCat, UDCMode.FORBIDDEN, Context.ORDINARY));
}
int cmp= c1.compareTo(null, cost1);
if (cmp <= 0) {
@ -663,9 +697,11 @@ public class Conversions {
}
}
}
if (s instanceof ICPPClassType) {
ICPPMethod[] ops = SemanticUtil.getConversionOperators((ICPPClassType) s);
CPPTemplates.instantiateConversionTemplates(ops, target);
final IType uqSource= getNestedType(source, TDEF | REF | CVTYPE);
if (uqSource instanceof ICPPClassType) {
ICPPMethod[] ops = SemanticUtil.getConversionOperators((ICPPClassType) uqSource);
CPPTemplates.instantiateConversionTemplates(ops, t);
for (final ICPPMethod op : ops) {
if (op != null && !(op instanceof IProblemBinding)) {
if (op.isExplicit())
@ -706,22 +742,25 @@ public class Conversions {
/**
* 13.3.1.5 Initialization by conversion function [over.match.conv]
*/
private static Cost initializationByConversion(IType source, ICPPClassType s, IType target, boolean direct) throws DOMException {
ICPPMethod[] ops = SemanticUtil.getConversionOperators(s);
static Cost initializationByConversion(ValueCategory valueCat, IType source, ICPPClassType uqSource, IType target, boolean deferUDC) throws DOMException {
if (deferUDC) {
Cost c= new Cost(source, target, Rank.USER_DEFINED_CONVERSION);
c.setDeferredUDC(DeferredUDC.INIT_BY_CONVERSION);
return c;
}
ICPPMethod[] ops = SemanticUtil.getConversionOperators(uqSource);
CPPTemplates.instantiateConversionTemplates(ops, target);
FunctionCost cost1= null;
Cost cost2= null;
for (final ICPPMethod op : ops) {
if (op != null && !(op instanceof IProblemBinding)) {
final boolean isExplicitConversion= op.isExplicit();
if (isExplicitConversion && !direct)
if (isExplicitConversion /** && !direct **/)
continue;
final IType returnType = op.getType().getReturnType();
IType uqReturnType= getNestedType(returnType, TDEF | ALLCVQ);
boolean isLValue = uqReturnType instanceof ICPPReferenceType
&& !((ICPPReferenceType) uqReturnType).isRValueReference();
Cost c2= checkImplicitConversionSequence(target, uqReturnType, isLValue, UDCMode.noUDC, false);
Cost c2= checkImplicitConversionSequence(target, uqReturnType, valueCategoryFromReturnType(uqReturnType), UDCMode.FORBIDDEN, Context.ORDINARY);
if (c2.converts()) {
if (isExplicitConversion && c2.getRank() != Rank.IDENTITY)
continue;
@ -756,33 +795,15 @@ public class Conversions {
* [4.2] array-to-ptr
* [4.3] function-to-ptr
*/
private static final boolean lvalue_to_rvalue(final Cost cost, boolean isLValue) {
// mstodo request value category
// target should not be a reference here.
boolean isConverted= false;
IType target = getNestedType(cost.target, REF | TDEF);
IType source= getNestedType(cost.source, REF | TDEF);
// 4.1 lvalue to rvalue
if (isLValue) {
// 4.1 lvalue of non-function and non-array
if (!(source instanceof IFunctionType) && !(source instanceof IArrayType)) {
// 4.1 if T is a non-class type, the type of the rvalue is the cv-unqualified version of T
IType unqualifiedSrcRValue= getNestedType(source, ALLCVQ | TDEF | REF);
if (unqualifiedSrcRValue instanceof ICPPClassType) {
cost.setRank(Rank.NO_MATCH);
return true;
} else {
source= unqualifiedSrcRValue;
}
isConverted= true;
}
}
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 | ALLCVQ);
// 4.2 array to pointer conversion
if (!isConverted && source instanceof IArrayType) {
if (source instanceof IArrayType) {
final IArrayType arrayType= (IArrayType) source;
boolean isConverted= false;
if (target instanceof IPointerType) {
final IType targetPtrTgt= getNestedType(((IPointerType) target).getType(), TDEF);
@ -807,16 +828,12 @@ public class Conversions {
}
if (!isConverted && (target instanceof IPointerType || target instanceof IBasicType)) {
source = new CPPPointerType(getNestedType(arrayType.getType(), TDEF));
isConverted= true;
}
}
// 4.3 function to pointer conversion
if (!isConverted && target instanceof IPointerType) {
} else if (target instanceof IPointerType) {
// 4.3 function to pointer conversion
final IType targetPtrTgt= getNestedType(((IPointerType) target).getType(), TDEF);
if (targetPtrTgt instanceof IFunctionType && source instanceof IFunctionType) {
source = new CPPPointerType(source);
isConverted= true;
}
}

View file

@ -30,6 +30,9 @@ import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPBasicType;
* See [over.best.ics] 13.3.3.1.
*/
class Cost {
public enum DeferredUDC {
NONE, COPY_INIT_OF_CLASS, INIT_BY_CONVERSION, LIST_INIT_OF_CLASS, DIRECT_LIST_INIT_OF_CLASS
}
enum Rank {
IDENTITY, PROMOTION, CONVERSION, CONVERSION_PTR_BOOL,
USER_DEFINED_CONVERSION, ELLIPSIS_CONVERSION, NO_MATCH
@ -52,7 +55,7 @@ class Cost {
assert false;
}
@Override
public void setDeferredUDC(boolean val) {
public void setDeferredUDC(DeferredUDC val) {
assert false;
}
@Override
@ -79,7 +82,7 @@ class Cost {
private Rank fRank;
private Rank fSecondStandardConversionRank;
private boolean fAmbiguousUDC;
private boolean fDeferredUDC;
private DeferredUDC fDeferredUDC= DeferredUDC.NONE;
private int fQualificationAdjustments;
private int fInheritanceDistance;
private ICPPFunction fUserDefinedConversion;
@ -119,12 +122,12 @@ class Cost {
fAmbiguousUDC= val;
}
public boolean isDeferredUDC() {
public DeferredUDC isDeferredUDC() {
return fDeferredUDC;
}
public void setDeferredUDC(boolean val) {
fDeferredUDC= val;
public void setDeferredUDC(DeferredUDC udc) {
fDeferredUDC= udc;
}
public int getInheritanceDistance() {
@ -160,7 +163,7 @@ class Cost {
return -1;
// cannot compare costs with deferred user defined conversions
assert !fDeferredUDC && !other.fDeferredUDC;
assert fDeferredUDC == DeferredUDC.NONE && other.fDeferredUDC == DeferredUDC.NONE;
int cmp= fRank.compareTo(other.fRank);
if (cmp != 0)
@ -218,8 +221,8 @@ class Cost {
buf.append(comma).append("inheritance=").append(fInheritanceDistance);
comma= ", ";
}
if (fDeferredUDC) {
buf.append(comma).append("deferred UDC");
if (fDeferredUDC != DeferredUDC.NONE) {
buf.append(comma).append(fDeferredUDC);
comma= ", ";
}
if (fAmbiguousUDC) {

View file

@ -10,13 +10,17 @@
*******************************************************************************/
package org.eclipse.cdt.internal.core.dom.parser.cpp.semantics;
import java.util.BitSet;
import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.*;
import org.eclipse.cdt.core.dom.ast.DOMException;
import org.eclipse.cdt.core.dom.ast.IASTExpression.ValueCategory;
import org.eclipse.cdt.core.dom.ast.IBinding;
import org.eclipse.cdt.core.dom.ast.IFunction;
import org.eclipse.cdt.core.dom.ast.IType;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassType;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPFunctionTemplate;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPSpecialization;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.Cost.DeferredUDC;
/**
* Cost for the entire function call
@ -24,18 +28,18 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPSpecialization;
class FunctionCost {
private final IFunction fFunction;
private final Cost[] fCosts;
private final BitSet fSourceIsLValue;
private final ValueCategory[] fValueCategories;
public FunctionCost(IFunction fn, int paramCount) {
fFunction= fn;
fCosts= new Cost[paramCount];
fSourceIsLValue= new BitSet(paramCount);
fValueCategories= new ValueCategory[paramCount];
}
public FunctionCost(IFunction fn, Cost cost) {
fFunction= fn;
fCosts= new Cost[] {cost};
fSourceIsLValue= null; // no udc will be performed
fValueCategories= null; // no udc will be performed
}
public int getLength() {
@ -46,9 +50,9 @@ class FunctionCost {
return fCosts[idx];
}
public void setCost(int idx, Cost cost, boolean sourceIsLValue) {
public void setCost(int idx, Cost cost, ValueCategory valueCat) {
fCosts[idx]= cost;
fSourceIsLValue.set(idx, sourceIsLValue);
fValueCategories[idx]= valueCat;
}
public IFunction getFunction() {
@ -67,7 +71,7 @@ class FunctionCost {
for (Cost cost : fCosts) {
if (!cost.converts())
return false;
if (cost.isDeferredUDC())
if (cost.isDeferredUDC() != DeferredUDC.NONE)
return true;
}
return false;
@ -76,13 +80,33 @@ class FunctionCost {
public boolean performUDC() throws DOMException {
for (int i = 0; i < fCosts.length; i++) {
Cost cost = fCosts[i];
if (cost.isDeferredUDC()) {
Cost udcCost = Conversions.checkUserDefinedConversionSequence(fSourceIsLValue.get(i),
cost.source, cost.target, false, false);
fCosts[i] = udcCost;
if (!udcCost.converts()) {
return false;
}
Cost udcCost= null;
switch(cost.isDeferredUDC()) {
case NONE:
continue;
case COPY_INIT_OF_CLASS:
udcCost = Conversions.copyInitializationOfClass(fValueCategories[i], cost.source,
(ICPPClassType) cost.target, false);
break;
case INIT_BY_CONVERSION:
IType uqSource= getNestedType(cost.source, TDEF | REF | CVTYPE);
udcCost = Conversions.initializationByConversion(fValueCategories[i], cost.source,
(ICPPClassType) uqSource, cost.target, false);
break;
case LIST_INIT_OF_CLASS:
udcCost = Conversions.listInitializationOfClass((InitializerListType) cost.source,
(ICPPClassType) cost.target, false, false);
break;
case DIRECT_LIST_INIT_OF_CLASS:
udcCost = Conversions.listInitializationOfClass((InitializerListType) cost.source,
(ICPPClassType) cost.target, true, false);
break;
default:
return false;
}
fCosts[i] = udcCost;
if (!udcCost.converts()) {
return false;
}
}
return true;
@ -163,7 +187,7 @@ class FunctionCost {
Cost otherCost= other.getCost(idxOther);
int cmp;
if (cost.isDeferredUDC()) {
if (cost.isDeferredUDC() != DeferredUDC.NONE) {
cmp= cost.getRank().compareTo(otherCost.getRank());
} else {
cmp= cost.compareTo(otherCost);

View file

@ -10,9 +10,8 @@
*******************************************************************************/
package org.eclipse.cdt.internal.core.dom.parser.cpp.semantics;
import java.util.BitSet;
import org.eclipse.cdt.core.dom.ast.IASTExpression;
import org.eclipse.cdt.core.dom.ast.IASTExpression.ValueCategory;
import org.eclipse.cdt.core.dom.ast.IASTInitializerClause;
import org.eclipse.cdt.core.dom.ast.IType;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTInitializerList;
@ -24,7 +23,7 @@ class InitializerListType implements IType {
private final ICPPASTInitializerList fInitializerList;
private IType[] fExpressionTypes;
private BitSet fLValues;
private ValueCategory[] fLValues;
public InitializerListType(ICPPASTInitializerList list) {
fInitializerList= list;
@ -66,16 +65,14 @@ class InitializerListType implements IType {
return fExpressionTypes;
}
public BitSet getIsLValue() {
public ValueCategory[] getValueCategories() {
if (fLValues == null) {
final IASTInitializerClause[] clauses = fInitializerList.getClauses();
fLValues= new BitSet(clauses.length);
fLValues= new ValueCategory[clauses.length];
for (int i = 0; i < clauses.length; i++) {
IASTInitializerClause clause = clauses[i];
if (clause instanceof IASTExpression) {
if (((IASTExpression) clause).isLValue()) {
fLValues.set(i);
}
fLValues[i]= ((IASTExpression) clause).getValueCategory();
}
}
}

View file

@ -14,7 +14,8 @@
*******************************************************************************/
package org.eclipse.cdt.internal.core.dom.parser.cpp.semantics;
import java.util.BitSet;
import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.ExpressionTypes.valueCategoryFromReturnType;
import java.util.Collections;
import java.util.List;
import java.util.Map;
@ -25,6 +26,7 @@ import org.eclipse.cdt.core.dom.ast.IASTCompositeTypeSpecifier;
import org.eclipse.cdt.core.dom.ast.IASTDeclaration;
import org.eclipse.cdt.core.dom.ast.IASTDeclarator;
import org.eclipse.cdt.core.dom.ast.IASTExpression;
import org.eclipse.cdt.core.dom.ast.IASTExpression.ValueCategory;
import org.eclipse.cdt.core.dom.ast.IASTFieldReference;
import org.eclipse.cdt.core.dom.ast.IASTFunctionCallExpression;
import org.eclipse.cdt.core.dom.ast.IASTFunctionDefinition;
@ -60,7 +62,6 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassScope;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassType;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPMethod;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPNamespaceScope;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPReferenceType;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPUsingDeclaration;
import org.eclipse.cdt.core.parser.util.ArrayUtil;
import org.eclipse.cdt.core.parser.util.CharArrayObjectMap;
@ -103,7 +104,7 @@ public class LookupData {
private ICPPASTParameterDeclaration[] functionParameters;
private IASTInitializerClause[] functionArgs;
private IType[] functionArgTypes;
private BitSet functionArgLValues;
private ValueCategory[] functionArgValueCategories;
public ICPPClassType skippedScope;
public Object foundItems = null;
@ -526,40 +527,37 @@ public class LookupData {
return functionArgTypes;
}
public BitSet getFunctionArgumentLValues() {
if (functionArgLValues == null) {
functionArgLValues= new BitSet();
IASTInitializerClause[] args= getFunctionArguments();
public ValueCategory[] getFunctionArgumentValueCategories() {
if (functionArgValueCategories == null) {
IASTInitializerClause[] args= functionArgs;
if (args != null) {
functionArgValueCategories= new ValueCategory[args.length];
for (int i = 0; i < args.length; i++) {
final IASTInitializerClause arg = args[i];
if (arg instanceof IASTExpression) {
functionArgLValues.set(i, ((IASTExpression) arg).isLValue());
} else {
functionArgLValues.set(i, false);
}
functionArgValueCategories[i]= ((IASTExpression) arg).getValueCategory();
}
}
} else {
IType[] argTypes= getFunctionArgumentTypes();
if (argTypes != null) {
functionArgValueCategories= new ValueCategory[argTypes.length];
for (int i = 0; i < argTypes.length; i++) {
IType t= argTypes[i];
functionArgLValues.set(i, t instanceof ICPPReferenceType && !((ICPPReferenceType) t).isRValueReference());
functionArgValueCategories[i]= valueCategoryFromReturnType(t);
}
} else {
functionArgValueCategories= new ValueCategory[0];
}
}
}
return functionArgLValues;
return functionArgValueCategories;
}
public void setFunctionParameters(ICPPASTParameterDeclaration[] parameters) {
functionParameters= parameters;
}
public IASTInitializerClause[] getFunctionArguments() {
return functionArgs;
}
public int getFunctionArgumentCount() {
if (functionArgs != null)
return functionArgs.length;

View file

@ -10,16 +10,17 @@
*******************************************************************************/
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.SemanticUtil.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.BitSet;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
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.IBinding;
@ -60,7 +61,7 @@ public class TemplateArgumentDeduction {
* 14.8.2.1
*/
static ICPPTemplateArgument[] deduceForFunctionCall(ICPPFunctionTemplate template,
ICPPTemplateArgument[] tmplArgs, IType[] fnArgs, BitSet argIsLValue, CPPTemplateParameterMap map)
ICPPTemplateArgument[] tmplArgs, IType[] fnArgs, ValueCategory[] argIsLValue, CPPTemplateParameterMap map)
throws DOMException {
final ICPPTemplateParameter[] tmplParams = template.getTemplateParameters();
final int numTmplParams = tmplParams.length;
@ -151,7 +152,7 @@ public class TemplateArgumentDeduction {
* Deduces the mapping for the template parameters from the function parameters,
* returns <code>false</code> if there is no mapping.
*/
static boolean deduceFromFunctionArgs(ICPPFunctionTemplate template, IType[] fnArgs, BitSet argIsLValue,
static boolean deduceFromFunctionArgs(ICPPFunctionTemplate template, IType[] fnArgs, ValueCategory[] argIsLValue,
CPPTemplateParameterMap map, boolean checkExactMatch) {
try {
IType[] fnPars = template.getType().getParameterTypes();
@ -214,7 +215,8 @@ public class TemplateArgumentDeduction {
// lvalue, the type "lvalue reference to A" is used in place of A for type deduction.
isReferenceTypeParameter= true;
final ICPPReferenceType refPar = (ICPPReferenceType) par;
if (refPar.isRValueReference() && refPar.getType() instanceof ICPPTemplateParameter && argIsLValue.get(j)) {
if (refPar.isRValueReference() && refPar.getType() instanceof ICPPTemplateParameter &&
argIsLValue != null && argIsLValue[j] == LVALUE) {
arg= new CPPReferenceType(getSimplifiedType(arg), false);
} else {
arg= getArgumentTypeForDeduction(arg, true);