diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2CPPTests.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2CPPTests.java index 22d27399419..4f8e8145382 100644 --- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2CPPTests.java +++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2CPPTests.java @@ -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); + } } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTConditionalExpression.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTConditionalExpression.java index 78038424fc6..625bd78928a 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTConditionalExpression.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTConditionalExpression.java @@ -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; } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPSemantics.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPSemantics.java index e4f690818e2..d0dc8387057 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPSemantics.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPSemantics.java @@ -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)); diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPTemplates.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPTemplates.java index e5e75aa8b01..c75afefd90b 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPTemplates.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPTemplates.java @@ -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(); } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPVisitor.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPVisitor.java index 43361640af9..d90fb89e02d 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPVisitor.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPVisitor.java @@ -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; diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/Conversions.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/Conversions.java index c111f3ec1fc..44dda707a70 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/Conversions.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/Conversions.java @@ -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; } } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/Cost.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/Cost.java index 91f4a0fdd62..05d0f4fb91b 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/Cost.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/Cost.java @@ -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) { diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/FunctionCost.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/FunctionCost.java index f17abd145ff..55c33b2d906 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/FunctionCost.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/FunctionCost.java @@ -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); diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/InitializerListType.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/InitializerListType.java index 90f98de7dd2..fd4578cb33b 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/InitializerListType.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/InitializerListType.java @@ -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(); } } } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/LookupData.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/LookupData.java index ae45620150b..e12ed82da51 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/LookupData.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/LookupData.java @@ -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; diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/TemplateArgumentDeduction.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/TemplateArgumentDeduction.java index be46b38cd01..a9748f636d3 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/TemplateArgumentDeduction.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/TemplateArgumentDeduction.java @@ -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 false 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);