1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-08-04 23:05:47 +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.IASTFunctionDeclarator;
import org.eclipse.cdt.core.dom.ast.IASTFunctionDefinition; import org.eclipse.cdt.core.dom.ast.IASTFunctionDefinition;
import org.eclipse.cdt.core.dom.ast.IASTIdExpression; 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.IASTImplicitNameOwner;
import org.eclipse.cdt.core.dom.ast.IASTLabelStatement; import org.eclipse.cdt.core.dom.ast.IASTLabelStatement;
import org.eclipse.cdt.core.dom.ast.IASTLiteralExpression; import org.eclipse.cdt.core.dom.ast.IASTLiteralExpression;
@ -8915,4 +8916,25 @@ public class AST2CPPTests extends AST2BaseTest {
bh.assertProblem("fint(pe + pe);", 4); bh.assertProblem("fint(pe + pe);", 4);
bh.assertNonProblem("fint(p + p);", 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() { public IType getExpressionType() {
IASTExpression positiveExpression = getPositiveResultExpression(); IASTExpression positiveExpression = getPositiveResultExpression();
if (positiveExpression == null) { if (positiveExpression == null) {
@ -147,7 +147,7 @@ public class CPPASTConditionalExpression extends ASTNode implements IASTConditio
return t2; return t2;
} }
// mstodo // mstodo conditional operator (value category)
public ValueCategory getValueCategory() { public ValueCategory getValueCategory() {
return PRVALUE; return PRVALUE;
} }

View file

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

View file

@ -13,8 +13,9 @@
*******************************************************************************/ *******************************************************************************/
package org.eclipse.cdt.internal.core.dom.parser.cpp.semantics; 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.ArrayList;
import java.util.BitSet;
import java.util.Collections; import java.util.Collections;
import java.util.List; 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.IASTDeclarator;
import org.eclipse.cdt.core.dom.ast.IASTElaboratedTypeSpecifier; import org.eclipse.cdt.core.dom.ast.IASTElaboratedTypeSpecifier;
import org.eclipse.cdt.core.dom.ast.IASTExpression; 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.IASTFunctionDefinition;
import org.eclipse.cdt.core.dom.ast.IASTIdExpression; import org.eclipse.cdt.core.dom.ast.IASTIdExpression;
import org.eclipse.cdt.core.dom.ast.IASTInitializerClause; 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.ICPPUnknownClassInstance;
import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPUnknownClassType; import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPUnknownClassType;
import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPUnknownType; import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPUnknownType;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.Conversions.Context;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.Conversions.UDCMode; 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. * type instantiation.
*/ */
public class CPPTemplates { 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_DEFER = -1;
private static final int PACK_SIZE_FAIL = -2; private static final int PACK_SIZE_FAIL = -2;
private static final int PACK_SIZE_NOT_FOUND = Integer.MAX_VALUE; 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, static protected void instantiateFunctionTemplates(IFunction[] functions, IType[] allFnArgs,
BitSet allArgIsLValue, IASTName name, boolean argsContainImpliedObject) { ValueCategory[] allValueCategories, IASTName name, boolean argsContainImpliedObject) {
boolean requireTemplate= false; boolean requireTemplate= false;
if (name != null) { if (name != null) {
if (name.getPropertyInParent() == ICPPASTTemplateId.TEMPLATE_NAME) { if (name.getPropertyInParent() == ICPPASTTemplateId.TEMPLATE_NAME) {
@ -1551,7 +1553,7 @@ public class CPPTemplates {
} }
IType[] reducedFnArgs= null; IType[] reducedFnArgs= null;
BitSet reducedIsLValue= null; ValueCategory[] reducedValueCategories= null;
ICPPTemplateArgument[] tmplArgs= null; ICPPTemplateArgument[] tmplArgs= null;
for (int i = 0; i < functions.length; i++) { for (int i = 0; i < functions.length; i++) {
IFunction func = functions[i]; IFunction func = functions[i];
@ -1560,23 +1562,23 @@ public class CPPTemplates {
functions[i]= null; functions[i]= null;
final IType[] fnArgs; final IType[] fnArgs;
final BitSet argIsLValue; final ValueCategory[] valueCategories;
if (argsContainImpliedObject && template instanceof ICPPMethod) { if (argsContainImpliedObject && template instanceof ICPPMethod) {
if (reducedIsLValue == null) { if (reducedValueCategories == null) {
if (allFnArgs != null && allFnArgs.length > 0) { if (allFnArgs != null && allFnArgs.length > 0) {
reducedFnArgs= ArrayUtil.removeFirst(allFnArgs); reducedFnArgs= ArrayUtil.removeFirst(allFnArgs);
} }
if (allArgIsLValue == null || allArgIsLValue.length() == 0) { if (allValueCategories == null || allValueCategories.length == 0) {
reducedIsLValue= ALL_RVALUES; reducedValueCategories= new ValueCategory[0];
} else { } else {
reducedIsLValue= allArgIsLValue.get(1, allArgIsLValue.length()); reducedValueCategories= ArrayUtil.removeFirst(allValueCategories);
} }
} }
fnArgs= reducedFnArgs; fnArgs= reducedFnArgs;
argIsLValue= reducedIsLValue; valueCategories= reducedValueCategories;
} else { } else {
fnArgs= allFnArgs; fnArgs= allFnArgs;
argIsLValue= allArgIsLValue; valueCategories= allValueCategories;
} }
// extract template arguments and parameter types. // extract template arguments and parameter types.
@ -1600,7 +1602,7 @@ public class CPPTemplates {
} }
CPPTemplateParameterMap map= new CPPTemplateParameterMap(fnArgs.length); CPPTemplateParameterMap map= new CPPTemplateParameterMap(fnArgs.length);
try { try {
ICPPTemplateArgument[] args= TemplateArgumentDeduction.deduceForFunctionCall(template, tmplArgs, fnArgs, argIsLValue, map); ICPPTemplateArgument[] args= TemplateArgumentDeduction.deduceForFunctionCall(template, tmplArgs, fnArgs, valueCategories, map);
if (args != null) { if (args != null) {
IBinding instance= instantiateFunctionTemplate(template, args, map); IBinding instance= instantiateFunctionTemplate(template, args, map);
if (instance instanceof IFunction) { if (instance instanceof IFunction) {
@ -1719,7 +1721,7 @@ public class CPPTemplates {
map= new CPPTemplateParameterMap(2); map= new CPPTemplateParameterMap(2);
final IType[] transferredParameterTypes = ((ICPPFunction) transferredTemplate).getType().getParameterTypes(); 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; return false;
final int last = tmplParams1.length -1; final int last = tmplParams1.length -1;
@ -1981,7 +1983,7 @@ public class CPPTemplates {
} else if (paramType instanceof IArrayType) { } else if (paramType instanceof IArrayType) {
paramType = new CPPPointerType(((IArrayType) paramType).getType()); paramType = new CPPPointerType(((IArrayType) paramType).getType());
} }
Cost cost = Conversions.checkImplicitConversionSequence(paramType, arg, true, UDCMode.noUDC, false); Cost cost = Conversions.checkImplicitConversionSequence(paramType, arg, LVALUE, UDCMode.FORBIDDEN, Context.ORDINARY);
return cost != null && cost.converts(); 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 static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.*;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.BitSet;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Set; 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.IASTEnumerationSpecifier.IASTEnumerator;
import org.eclipse.cdt.core.dom.ast.IASTEqualsInitializer; import org.eclipse.cdt.core.dom.ast.IASTEqualsInitializer;
import org.eclipse.cdt.core.dom.ast.IASTExpression; 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.IASTFieldReference;
import org.eclipse.cdt.core.dom.ast.IASTForStatement; import org.eclipse.cdt.core.dom.ast.IASTForStatement;
import org.eclipse.cdt.core.dom.ast.IASTFunctionCallExpression; import org.eclipse.cdt.core.dom.ast.IASTFunctionCallExpression;
@ -1791,6 +1791,7 @@ public class CPPVisitor extends ASTQueries {
IType type = AutoTypeResolver.AUTO_TYPE; IType type = AutoTypeResolver.AUTO_TYPE;
IType initType = null; IType initType = null;
ValueCategory valueCat= null;
ICPPClassTemplate initializer_list_template = null; ICPPClassTemplate initializer_list_template = null;
try { try {
if (initClause instanceof ICPPASTInitializerList) { if (initClause instanceof ICPPASTInitializerList) {
@ -1804,7 +1805,9 @@ public class CPPVisitor extends ASTQueries {
type = decorateType(type, declSpec, declarator); type = decorateType(type, declSpec, declarator);
if (initClause instanceof IASTExpression) { if (initClause instanceof IASTExpression) {
initType = ((IASTExpression) initClause).getExpressionType(); final IASTExpression expression = (IASTExpression) initClause;
initType = expression.getExpressionType();
valueCat= expression.getValueCategory();
} else if (initClause instanceof ICPPASTInitializerList) { } else if (initClause instanceof ICPPASTInitializerList) {
initType = new InitializerListType((ICPPASTInitializerList) initClause); initType = new InitializerListType((ICPPASTInitializerList) initClause);
} }
@ -1816,8 +1819,8 @@ public class CPPVisitor extends ASTQueries {
} }
ICPPFunctionTemplate template = new AutoTypeResolver(type); ICPPFunctionTemplate template = new AutoTypeResolver(type);
CPPTemplateParameterMap paramMap = new CPPTemplateParameterMap(1); CPPTemplateParameterMap paramMap = new CPPTemplateParameterMap(1);
TemplateArgumentDeduction.deduceFromFunctionArgs(template, new IType[] { initType }, new BitSet(), TemplateArgumentDeduction.deduceFromFunctionArgs(template, new IType[] { initType },
paramMap, false); new ValueCategory[] { valueCat }, paramMap, false);
ICPPTemplateArgument argument = paramMap.getArgument(0, 0); ICPPTemplateArgument argument = paramMap.getArgument(0, 0);
if (argument == null) { if (argument == null) {
return null; return null;

View file

@ -14,13 +14,14 @@
*******************************************************************************/ *******************************************************************************/
package org.eclipse.cdt.internal.core.dom.parser.cpp.semantics; 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.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 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.DOMException;
import org.eclipse.cdt.core.dom.ast.IASTExpression; 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.IASTInitializerClause;
import org.eclipse.cdt.core.dom.ast.IASTLiteralExpression; import org.eclipse.cdt.core.dom.ast.IASTLiteralExpression;
import org.eclipse.cdt.core.dom.ast.IASTName; import org.eclipse.cdt.core.dom.ast.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.CPPPointerToMemberType;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPPointerType; 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.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.Rank;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.Cost.ReferenceBinding; 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. * Routines for calculating the cost of conversions.
*/ */
public class 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[] INITIALIZER_LIST_NAME = "initializer_list".toCharArray(); //$NON-NLS-1$
private static final char[] STD_NAME = "std".toCharArray(); //$NON-NLS-1$ private static final char[] STD_NAME = "std".toCharArray(); //$NON-NLS-1$
/** /**
* Computes the cost of an implicit conversion sequence * Computes the cost of an implicit conversion sequence [over.best.ics] 13.3.3.1
* [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 target the target (parameter) type
* @param exprType the source (argument) type * @param exprType the source (argument) type
* @param exprIsLValue whether the source type is an lvalue * @param valueCat value category of the expression
* @param isImpliedObjectType
* @return the cost of converting from source to target * @return the cost of converting from source to target
* @throws DOMException * @throws DOMException
*/ */
public static Cost checkImplicitConversionSequence(IType target, IType exprType, public static Cost checkImplicitConversionSequence(IType target, IType exprType,
boolean exprIsLValue, UDCMode udc, boolean isImpliedObjectType) throws DOMException { ValueCategory valueCat, UDCMode udc, Context ctx) throws DOMException {
if (isImpliedObjectType) { final boolean isImpliedObject= ctx == Context.IMPLICIT_OBJECT;
udc= UDCMode.noUDC; if (isImpliedObject) {
udc= UDCMode.FORBIDDEN;
} }
target= getNestedType(target, TDEF); target= getNestedType(target, TDEF);
@ -99,12 +97,13 @@ public class Conversions {
final IType cv2T2= exprType; final IType cv2T2= exprType;
final IType T2= getNestedType(cv2T2, TDEF | REF | ALLCVQ); 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; ReferenceBinding refBindingType= ReferenceBinding.OTHER;
if (!isImplicitWithoutRefQualifier) { if (!isImplicitWithoutRefQualifier) {
if (isLValueRef) { if (isLValueRef) {
refBindingType= ReferenceBinding.LVALUE_REF; refBindingType= ReferenceBinding.LVALUE_REF;
} else if (exprIsLValue) { } else if (valueCat == LVALUE) {
refBindingType= ReferenceBinding.RVALUE_REF_BINDS_RVALUE; refBindingType= ReferenceBinding.RVALUE_REF_BINDS_RVALUE;
} }
} }
@ -113,9 +112,9 @@ public class Conversions {
if (isLValueRef) { if (isLValueRef) {
// ... the initializer expression is an lvalue (but is not a bit field) // ... 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] // [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" // ... and "cv1 T1" is reference-compatible with "cv2 T2"
Cost cost= isReferenceCompatible(cv1T1, cv2T2, isImpliedObjectType); Cost cost= isReferenceCompatible(cv1T1, cv2T2, isImpliedObject);
if (cost != null) { if (cost != null) {
// [13.3.3.1.4-1] direct binding has either identity or conversion rank. // [13.3.3.1.4-1] direct binding has either identity or conversion rank.
if (cost.getInheritanceDistance() > 0) { 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 // 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) // '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)), // and choosing the best one through overload resolution (13.3)),
if (T2 instanceof ICPPClassType && udc != UDCMode.noUDC && isReferenceRelated(T1, T2) < 0) { if (T2 instanceof ICPPClassType && udc != UDCMode.FORBIDDEN && isReferenceRelated(T1, T2) < 0) {
Cost cost= conversionFuncForDirectReference(cv1T1, cv2T2, T2, true); Cost cost= initializationByConversionForDirectReference(cv1T1, cv2T2, (ICPPClassType) T2, true, ctx);
if (cost != null) { if (cost != null) {
cost.setReferenceBinding(refBindingType); cost.setReferenceBinding(refBindingType);
return cost; 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 // 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 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; boolean ok;
if (isLValueRef) { if (isLValueRef) {
ok = getCVQualifier(cv1T1) == CVQualifier.c; ok = getCVQualifier(cv1T1) == CVQualifier.c;
} else { } else {
ok= !exprIsLValue; ok= valueCat.isRValue() || T2 instanceof IFunctionType;
} }
if (!ok) { if (!ok) {
return Cost.NO_CONVERSION; return Cost.NO_CONVERSION;
} }
// If T1 and T2 are class types and ... // If T1 is a function type, then
if (T1 instanceof ICPPClassType && T2 instanceof ICPPClassType) { if (T1 instanceof IFunctionType) {
// ... the initializer expression is an rvalue and cv1 T1 is reference-compatible with cv2 T2 // if T2 is the same type as T1, the reference is bound to the initializer expression lvalue;
if (!exprIsLValue) { if (T2.isSameType(T1)) {
Cost cost= isReferenceCompatible(cv1T1, cv2T2, isImpliedObjectType); 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) { if (cost != null) {
// [13.3.3.1.4-1] direct binding has either identity or conversion rank. // [13.3.3.1.4-1] direct binding has either identity or conversion rank.
if (cost.getInheritanceDistance() > 0) { 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 // 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 // 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 // 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, // 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). // in either case, to the appropriate base class sub-object of the object).
if (udc != UDCMode.noUDC && isReferenceRelated(T1, T2) < 0) { if (udc != UDCMode.FORBIDDEN && isReferenceRelated(T1, T2) < 0) {
Cost cost= conversionFuncForDirectReference(cv1T1, cv2T2, T2, false); Cost cost= initializationByConversionForDirectReference(cv1T1, cv2T2, (ICPPClassType) T2, false, ctx);
if (cost != null) { if (cost != null) {
cost.setReferenceBinding(refBindingType); cost.setReferenceBinding(refBindingType);
return cost; 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 // 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 // reference-compatible with 'cv2 T2' the reference is bound to the object represented by the
// rvalue (see 3.10). // rvalue (see 3.10).
if (!exprIsLValue && T2 instanceof IArrayType) { if (T2 instanceof IArrayType && valueCat.isRValue()) {
Cost cost= isReferenceCompatible(cv1T1, cv2T2, isImpliedObjectType); Cost cost= isReferenceCompatible(cv1T1, cv2T2, isImpliedObject);
if (cost != null) { if (cost != null) {
cost.setReferenceBinding(refBindingType); cost.setReferenceBinding(refBindingType);
return cost; return cost;
@ -198,9 +221,9 @@ public class Conversions {
// as, or greater cv-qualification than, cv2; otherwise, the program is ill-formed. // 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 // 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) { 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()) { if (!isImplicitWithoutRefQualifier && cost.converts()) {
cost.setReferenceBinding(isLValueRef ? ReferenceBinding.LVALUE_REF : ReferenceBinding.RVALUE_REF_BINDS_RVALUE); 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 * 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 { throws DOMException {
ICPPMethod[] fcns= SemanticUtil.getConversionOperators((ICPPClassType) T2); ICPPMethod[] fcns= SemanticUtil.getConversionOperators(T2);
Cost operatorCost= null; Cost operatorCost= null;
FunctionCost bestUdcCost= null; FunctionCost bestUdcCost= null;
boolean ambiguousConversionOperator= false; boolean ambiguousConversionOperator= false;
if (fcns.length > 0 && !(fcns[0] instanceof IProblemBinding)) { if (fcns.length > 0 && !(fcns[0] instanceof IProblemBinding)) {
for (final ICPPMethod op : fcns) { 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(); final ICPPFunctionType ft = op.getType();
IType convertedType= ft.getReturnType(); IType t= getNestedType(ft.getReturnType(), TDEF);
final boolean isLValue = CPPVisitor.isLValueReference(convertedType); final boolean isLValueRef= t instanceof ICPPReferenceType && !((ICPPReferenceType) t).isRValueReference();
if (isLValue == forLValue) { // require an lvalue or rvalue if (isLValueRef == needLValue) { // require an lvalue or rvalue
IType implicitObjectType= CPPSemantics.getImplicitParameterType(op, ft.isConst(), ft.isVolatile()); IType implicitParameterType= CPPSemantics.getImplicitParameterType(op, ft.isConst(), ft.isVolatile());
Cost udcCost= isReferenceCompatible(getNestedType(implicitObjectType, TDEF | REF), cv2T2, true); // expression type to implicit object type Cost udcCost= isReferenceCompatible(getNestedType(implicitParameterType, TDEF | REF), cv2T2, true); // expression type to implicit object type
if (udcCost != null) { if (udcCost != null) {
FunctionCost udcFuncCost= new FunctionCost(op, udcCost); FunctionCost udcFuncCost= new FunctionCost(op, udcCost);
int cmp= udcFuncCost.compareTo(null, bestUdcCost); int cmp= udcFuncCost.compareTo(null, bestUdcCost);
if (cmp <= 0) { 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) { if (cost != null) {
bestUdcCost= udcFuncCost; bestUdcCost= udcFuncCost;
ambiguousConversionOperator= cmp == 0; ambiguousConversionOperator= cmp == 0;
@ -270,18 +298,43 @@ public class Conversions {
return null; 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) { if (source instanceof InitializerListType) {
return listInitializationSequence(((InitializerListType) source), target, udc, false); return listInitializationSequence(((InitializerListType) source), target, udc, false);
} }
// [13.3.3.1-6] Subsume cv-qualifications
IType uqSource= SemanticUtil.getNestedType(source, TDEF | ALLCVQ); IType uqTarget= SemanticUtil.getNestedType(target, TDEF | REF | CVTYPE);
Cost cost= checkStandardConversionSequence(uqSource, sourceIsLValue, target, isImpliedObject); IType uqSource= SemanticUtil.getNestedType(source, TDEF | REF | CVTYPE);
if (cost.converts() || udc == UDCMode.noUDC) if (uqTarget instanceof ICPPClassType) {
return cost; 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); IType listType= getInitListType(target);
if (listType != null) { if (listType != null) {
IType[] exprTypes= arg.getExpressionTypes(); IType[] exprTypes= arg.getExpressionTypes();
BitSet isLValue= arg.getIsLValue(); ValueCategory[] valueCats= arg.getValueCategories();
Cost worstCost= new Cost(arg, target, Rank.IDENTITY); Cost worstCost= new Cost(arg, target, Rank.IDENTITY);
for (int i = 0; i < exprTypes.length; i++) { for (int i = 0; i < exprTypes.length; i++) {
IType exprType = exprTypes[i]; IType exprType = exprTypes[i];
Cost cost= checkImplicitConversionSequence(listType, exprType, isLValue.get(i), UDCMode.allowUDC, false); Cost cost= checkImplicitConversionSequence(listType, exprType, valueCats[i], UDCMode.ALLOWED, Context.ORDINARY);
if (!cost.converts()) if (!cost.converts())
return cost; return cost;
if (cost.isNarrowingConversion()) { if (cost.isNarrowingConversion()) {
@ -311,7 +364,7 @@ public class Conversions {
IType noCVTarget= getNestedType(target, CVTYPE | TDEF); IType noCVTarget= getNestedType(target, CVTYPE | TDEF);
if (noCVTarget instanceof ICPPClassType) { if (noCVTarget instanceof ICPPClassType) {
if (udc == UDCMode.noUDC) if (udc == UDCMode.FORBIDDEN)
return Cost.NO_CONVERSION; return Cost.NO_CONVERSION;
ICPPClassType classTarget= (ICPPClassType) noCVTarget; ICPPClassType classTarget= (ICPPClassType) noCVTarget;
@ -320,7 +373,7 @@ public class Conversions {
cost.setUserDefinedConversion(null); cost.setUserDefinedConversion(null);
return cost; return cost;
} }
return checkUserDefinedConversionSequence(false, arg, target, udc == UDCMode.deferUDC, isDirect); return listInitializationOfClass(arg, classTarget, isDirect, udc == UDCMode.DEFER);
} }
IASTInitializerClause[] args = arg.getInitializerList().getClauses(); IASTInitializerClause[] args = arg.getInitializerList().getClauses();
@ -328,7 +381,7 @@ public class Conversions {
final IASTInitializerClause firstArg = args[0]; final IASTInitializerClause firstArg = args[0];
if (firstArg instanceof IASTExpression) { if (firstArg instanceof IASTExpression) {
IASTExpression expr= (IASTExpression) firstArg; 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()) { if (cost.isNarrowingConversion()) {
return Cost.NO_CONVERSION; return Cost.NO_CONVERSION;
} }
@ -484,10 +537,9 @@ public class Conversions {
* classes are nominated via using-declarations. In such a situation the derived to * classes are nominated via using-declarations. In such a situation the derived to
* base conversion does not cause any costs. * base conversion does not cause any costs.
*/ */
private static final Cost checkStandardConversionSequence(IType source, boolean isLValue, IType target, private static final Cost checkStandardConversionSequence(IType source, IType target, boolean isImplicitThis) {
boolean isImplicitThis) {
final Cost cost= new Cost(source, target, Rank.IDENTITY); final Cost cost= new Cost(source, target, Rank.IDENTITY);
if (lvalue_to_rvalue(cost, isLValue)) if (lvalue_to_rvalue(cost))
return cost; return cost;
if (promotion(cost)) if (promotion(cost))
@ -504,40 +556,14 @@ public class Conversions {
return cost; return cost;
} }
/** // 13.3.1.7 Initialization by list-initialization
* [13.3.3.1.2] User-defined conversions static Cost listInitializationOfClass(InitializerListType arg, ICPPClassType t, boolean isDirect, boolean deferUDC) throws DOMException {
*/
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;
}
if (deferUDC) { if (deferUDC) {
Cost c= new Cost(source, target, Rank.USER_DEFINED_CONVERSION); Cost c= new Cost(arg, t, Rank.USER_DEFINED_CONVERSION);
c.setDeferredUDC(true); c.setDeferredUDC(isDirect ? DeferredUDC.DIRECT_LIST_INIT_OF_CLASS : DeferredUDC.LIST_INIT_OF_CLASS);
return c; 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 // If T has an initializer-list constructor
ICPPConstructor usedCtor= null; ICPPConstructor usedCtor= null;
Cost bestCost= null; Cost bestCost= null;
@ -551,7 +577,7 @@ public class Conversions {
final IType target = parTypes[0]; final IType target = parTypes[0];
if (getInitListType(target) != null) { if (getInitListType(target) != null) {
hasInitListConstructor= true; hasInitListConstructor= true;
Cost cost= listInitializationSequence(arg, target, UDCMode.noUDC, isDirect); Cost cost= listInitializationSequence(arg, target, UDCMode.FORBIDDEN, isDirect);
if (cost.converts()) { if (cost.converts()) {
int cmp= cost.compareTo(bestCost); int cmp= cost.compareTo(bestCost);
if (bestCost == null || cmp < 0) { 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] * 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, static final Cost copyInitializationOfClass(ValueCategory valueCat, IType source, ICPPClassType t, boolean deferUDC) throws DOMException {
ICPPClassType t) 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; FunctionCost cost1= null;
Cost cost2= null; Cost cost2= null;
ICPPConstructor[] ctors= t.getConstructors(); 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) { 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()) { if (ctor != null && !(ctor instanceof IProblemBinding) && !ctor.isExplicit()) {
final ICPPFunctionType ft = ctor.getType(); final ICPPFunctionType ft = ctor.getType();
final IType[] ptypes = ft.getParameterTypes(); final IType[] ptypes = ft.getParameterTypes();
@ -650,7 +684,7 @@ public class Conversions {
if (ctor.getRequiredArgumentCount() > 1) if (ctor.getRequiredArgumentCount() > 1)
continue; 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); int cmp= c1.compareTo(null, cost1);
if (cmp <= 0) { if (cmp <= 0) {
@ -663,9 +697,11 @@ public class Conversions {
} }
} }
} }
if (s instanceof ICPPClassType) {
ICPPMethod[] ops = SemanticUtil.getConversionOperators((ICPPClassType) s); final IType uqSource= getNestedType(source, TDEF | REF | CVTYPE);
CPPTemplates.instantiateConversionTemplates(ops, target); if (uqSource instanceof ICPPClassType) {
ICPPMethod[] ops = SemanticUtil.getConversionOperators((ICPPClassType) uqSource);
CPPTemplates.instantiateConversionTemplates(ops, t);
for (final ICPPMethod op : ops) { for (final ICPPMethod op : ops) {
if (op != null && !(op instanceof IProblemBinding)) { if (op != null && !(op instanceof IProblemBinding)) {
if (op.isExplicit()) if (op.isExplicit())
@ -706,22 +742,25 @@ public class Conversions {
/** /**
* 13.3.1.5 Initialization by conversion function [over.match.conv] * 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 { static Cost initializationByConversion(ValueCategory valueCat, IType source, ICPPClassType uqSource, IType target, boolean deferUDC) throws DOMException {
ICPPMethod[] ops = SemanticUtil.getConversionOperators(s); 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); CPPTemplates.instantiateConversionTemplates(ops, target);
FunctionCost cost1= null; FunctionCost cost1= null;
Cost cost2= null; Cost cost2= null;
for (final ICPPMethod op : ops) { for (final ICPPMethod op : ops) {
if (op != null && !(op instanceof IProblemBinding)) { if (op != null && !(op instanceof IProblemBinding)) {
final boolean isExplicitConversion= op.isExplicit(); final boolean isExplicitConversion= op.isExplicit();
if (isExplicitConversion && !direct) if (isExplicitConversion /** && !direct **/)
continue; continue;
final IType returnType = op.getType().getReturnType(); final IType returnType = op.getType().getReturnType();
IType uqReturnType= getNestedType(returnType, TDEF | ALLCVQ); IType uqReturnType= getNestedType(returnType, TDEF | ALLCVQ);
boolean isLValue = uqReturnType instanceof ICPPReferenceType Cost c2= checkImplicitConversionSequence(target, uqReturnType, valueCategoryFromReturnType(uqReturnType), UDCMode.FORBIDDEN, Context.ORDINARY);
&& !((ICPPReferenceType) uqReturnType).isRValueReference();
Cost c2= checkImplicitConversionSequence(target, uqReturnType, isLValue, UDCMode.noUDC, false);
if (c2.converts()) { if (c2.converts()) {
if (isExplicitConversion && c2.getRank() != Rank.IDENTITY) if (isExplicitConversion && c2.getRank() != Rank.IDENTITY)
continue; continue;
@ -756,33 +795,15 @@ public class Conversions {
* [4.2] array-to-ptr * [4.2] array-to-ptr
* [4.3] function-to-ptr * [4.3] function-to-ptr
*/ */
private static final boolean lvalue_to_rvalue(final Cost cost, boolean isLValue) { private static final boolean lvalue_to_rvalue(final Cost cost) {
// mstodo request value category IType target = getNestedType(cost.target, REF | TDEF | ALLCVQ);
// target should not be a reference here. IType source= getNestedType(cost.source, REF | TDEF | ALLCVQ);
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;
}
}
// 4.2 array to pointer conversion // 4.2 array to pointer conversion
if (!isConverted && source instanceof IArrayType) { if (source instanceof IArrayType) {
final IArrayType arrayType= (IArrayType) source; final IArrayType arrayType= (IArrayType) source;
boolean isConverted= false;
if (target instanceof IPointerType) { if (target instanceof IPointerType) {
final IType targetPtrTgt= getNestedType(((IPointerType) target).getType(), TDEF); final IType targetPtrTgt= getNestedType(((IPointerType) target).getType(), TDEF);
@ -807,16 +828,12 @@ public class Conversions {
} }
if (!isConverted && (target instanceof IPointerType || target instanceof IBasicType)) { if (!isConverted && (target instanceof IPointerType || target instanceof IBasicType)) {
source = new CPPPointerType(getNestedType(arrayType.getType(), TDEF)); source = new CPPPointerType(getNestedType(arrayType.getType(), TDEF));
isConverted= true;
} }
} } else if (target instanceof IPointerType) {
// 4.3 function to pointer conversion
// 4.3 function to pointer conversion
if (!isConverted && target instanceof IPointerType) {
final IType targetPtrTgt= getNestedType(((IPointerType) target).getType(), TDEF); final IType targetPtrTgt= getNestedType(((IPointerType) target).getType(), TDEF);
if (targetPtrTgt instanceof IFunctionType && source instanceof IFunctionType) { if (targetPtrTgt instanceof IFunctionType && source instanceof IFunctionType) {
source = new CPPPointerType(source); 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. * See [over.best.ics] 13.3.3.1.
*/ */
class Cost { class Cost {
public enum DeferredUDC {
NONE, COPY_INIT_OF_CLASS, INIT_BY_CONVERSION, LIST_INIT_OF_CLASS, DIRECT_LIST_INIT_OF_CLASS
}
enum Rank { enum Rank {
IDENTITY, PROMOTION, CONVERSION, CONVERSION_PTR_BOOL, IDENTITY, PROMOTION, CONVERSION, CONVERSION_PTR_BOOL,
USER_DEFINED_CONVERSION, ELLIPSIS_CONVERSION, NO_MATCH USER_DEFINED_CONVERSION, ELLIPSIS_CONVERSION, NO_MATCH
@ -52,7 +55,7 @@ class Cost {
assert false; assert false;
} }
@Override @Override
public void setDeferredUDC(boolean val) { public void setDeferredUDC(DeferredUDC val) {
assert false; assert false;
} }
@Override @Override
@ -79,7 +82,7 @@ class Cost {
private Rank fRank; private Rank fRank;
private Rank fSecondStandardConversionRank; private Rank fSecondStandardConversionRank;
private boolean fAmbiguousUDC; private boolean fAmbiguousUDC;
private boolean fDeferredUDC; private DeferredUDC fDeferredUDC= DeferredUDC.NONE;
private int fQualificationAdjustments; private int fQualificationAdjustments;
private int fInheritanceDistance; private int fInheritanceDistance;
private ICPPFunction fUserDefinedConversion; private ICPPFunction fUserDefinedConversion;
@ -119,12 +122,12 @@ class Cost {
fAmbiguousUDC= val; fAmbiguousUDC= val;
} }
public boolean isDeferredUDC() { public DeferredUDC isDeferredUDC() {
return fDeferredUDC; return fDeferredUDC;
} }
public void setDeferredUDC(boolean val) { public void setDeferredUDC(DeferredUDC udc) {
fDeferredUDC= val; fDeferredUDC= udc;
} }
public int getInheritanceDistance() { public int getInheritanceDistance() {
@ -160,7 +163,7 @@ class Cost {
return -1; return -1;
// cannot compare costs with deferred user defined conversions // 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); int cmp= fRank.compareTo(other.fRank);
if (cmp != 0) if (cmp != 0)
@ -218,8 +221,8 @@ class Cost {
buf.append(comma).append("inheritance=").append(fInheritanceDistance); buf.append(comma).append("inheritance=").append(fInheritanceDistance);
comma= ", "; comma= ", ";
} }
if (fDeferredUDC) { if (fDeferredUDC != DeferredUDC.NONE) {
buf.append(comma).append("deferred UDC"); buf.append(comma).append(fDeferredUDC);
comma= ", "; comma= ", ";
} }
if (fAmbiguousUDC) { if (fAmbiguousUDC) {

View file

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

View file

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

View file

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

View file

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