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 969649a3d68..0fd7b12653e 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 @@ -8077,5 +8077,68 @@ public class AST2CPPTests extends AST2BaseTest { String code= getAboveComment(); parseAndCheckBindings(code, ParserLanguage.CPP); } + + // namespace std { + // template class initializer_list; + // } + // template struct complex { + // complex(const T& r, const T& i); + // }; + // template struct vector { + // vector(std::initializer_list); + // }; + // struct str { + // str(const char*); + // }; + // template void f(std::initializer_list); + // std::initializer_list test() { + // int a = {1}; + // complex z{1,2}; + // new vector{"a", "b", "c", "d"}; // 4 string elements + // f( {"a","b"} ); // pass list of two elements + // int* e {}; // initialization to zero / null pointer + // a = double{1}; // explicitly construct a double + // return { "a" }; // return list of one element + // } + // + // struct S { + // S(std::initializer_list) {} + // S(std::initializer_list) {} + // }; + // void fs(S){} + // void tests() { + // fs({1,2,3}); + // fs({1.0,2.0,3.0}); + // } + public void _testListInitialization_302412a() throws Exception { + String code= getAboveComment(); + parseAndCheckBindings(code, ParserLanguage.CPP); + } + + // namespace std { + // template class initializer_list; + // } + // void f(std::initializer_list); + // //void ff(std::initializer_list); + // struct A { + // A(std::initializer_list); // #1 + // A(std::initializer_list); // #3 + // }; + // void g(A); + // void test() { + // f( {1,2,3} ); // OK: f(initializer_list) identity conversion + // f( {'a','b'} ); // OK: f(initializer_list) integral promotion + // f( {1.0} ); // error: narrowing + // A a{ 1.0,2.0 }; // OK, uses #1 + // g({ "foo", "bar" }); // OK, uses #3 + // } + public void testListInitialization_302412b() throws Exception { + String code= getAboveComment(); + BindingAssertionHelper bh= new BindingAssertionHelper(code, true); + bh.assertNonProblem("f( {1,2,3} )", 1); + bh.assertNonProblem("f( {'a','b'} )", 1); + bh.assertProblem("f( {1.0} )", 1); + bh.assertNonProblem("g({ \"foo\", \"bar\" })", 1); + } } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTFunctionCallExpression.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTFunctionCallExpression.java index 3155097b477..c733370c585 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTFunctionCallExpression.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTFunctionCallExpression.java @@ -16,9 +16,9 @@ import org.eclipse.cdt.core.dom.ast.ASTVisitor; import org.eclipse.cdt.core.dom.ast.DOMException; import org.eclipse.cdt.core.dom.ast.ExpansionOverlapsBoundaryException; import org.eclipse.cdt.core.dom.ast.IASTExpression; -import org.eclipse.cdt.core.dom.ast.IASTInitializerClause; import org.eclipse.cdt.core.dom.ast.IASTIdExpression; import org.eclipse.cdt.core.dom.ast.IASTImplicitName; +import org.eclipse.cdt.core.dom.ast.IASTInitializerClause; import org.eclipse.cdt.core.dom.ast.IASTNode; import org.eclipse.cdt.core.dom.ast.IBinding; import org.eclipse.cdt.core.dom.ast.IFunction; @@ -64,7 +64,7 @@ public class CPPASTFunctionCallExpression extends ASTNode implements public CPPASTFunctionCallExpression copy() { IASTInitializerClause[] args = null; if (fArguments.length > 0) { - args= new IASTExpression[fArguments.length]; + args= new IASTInitializerClause[fArguments.length]; for (int i=0; i 0) + return false; + ICPPMethod[] methods = classTarget.getDeclaredMethods(); + for (ICPPMethod m : methods) { + if (m instanceof ICPPConstructor) + return false; + if (m.isVirtual()) { + return false; + } + } + ICPPField[] fields = classTarget.getDeclaredFields(); + for (ICPPField field : fields) { + if (!(field.getVisibility() == ICPPMember.v_public || field.isStatic())) { + return false; + } + } + return true; + } } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/GNUCPPSourceParser.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/GNUCPPSourceParser.java index e556229a4b4..4672ddbceec 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/GNUCPPSourceParser.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/GNUCPPSourceParser.java @@ -830,7 +830,7 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser { if (allowThrow && LT(1) == IToken.t_throw) { expr= throwExpression(); } else if (allowBraceInitializer && LT(1) == IToken.tLBRACE) { - expr= bracedInitList(); + expr= bracedInitList(true); } else { expr= castExpression(castCtx); // next cast expression continue loop; @@ -1162,7 +1162,7 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser { if (t != null) { consume(IToken.tRPAREN); if (LT(1) == IToken.tLBRACE) { - IASTInitializer i = bracedInitList(); + IASTInitializer i = bracedInitList(false); firstExpression= nodeFactory.newTypeIdInitializerExpression(t, i); setRange(firstExpression, offset, calculateEndOffset(i)); break; @@ -1212,7 +1212,7 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser { consume(IToken.tLBRACKET); IASTInitializerClause expression; if (LT(1) == IToken.tLBRACE) { - expression= bracedInitList(); + expression= bracedInitList(false); } else { expression= expression(); } @@ -2795,14 +2795,14 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser { // = initializer-clause if (lt1 == IToken.tASSIGN) { int offset= consume().getOffset(); - IASTInitializerClause initClause = initClause(false); + IASTInitializerClause initClause = initClause(LT(1) == IToken.tLBRACE); IASTEqualsInitializer initExpr= nodeFactory.newEqualsInitializer(initClause); return setRange(initExpr, offset, calculateEndOffset(initClause)); } // braced-init-list if (option.fAllowBracedInitializer && lt1 == IToken.tLBRACE) { - return bracedInitList(); + return bracedInitList(false); } // ( expression-list ) @@ -2817,7 +2817,7 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser { if (lt1 == IToken.tLPAREN) { return ctorStyleInitializer(true); } - return bracedInitList(); + return bracedInitList(false); } /** @@ -2848,17 +2848,17 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser { * assignment-expression * braced-init-list */ - private IASTInitializerClause initClause(boolean inBraces) throws EndOfFileException, + private IASTInitializerClause initClause(boolean allowSkipping) throws EndOfFileException, BacktrackException { // braced-init-list if (LT(1) == IToken.tLBRACE) { - return bracedInitList(); + return bracedInitList(allowSkipping); } // assignment expression final BinaryExprCtx ctx = fInTemplateParameterList ? BinaryExprCtx.eTmplID : BinaryExprCtx.eNoTmplID; IASTExpression assignmentExpression = expression(ExprKind.eAssignment, ctx); - if (inBraces && skipTrivialExpressionsInAggregateInitializers) { + if (allowSkipping && skipTrivialExpressionsInAggregateInitializers) { if (!ASTQueries.canContainName(assignmentExpression)) return null; } @@ -2870,7 +2870,7 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser { * { initializer-list ,opt } * { } */ - private ICPPASTInitializerList bracedInitList() throws EndOfFileException, BacktrackException { + private ICPPASTInitializerList bracedInitList(boolean allowSkipping) throws EndOfFileException, BacktrackException { int offset = consume(IToken.tLBRACE).getOffset(); // { } @@ -2879,7 +2879,7 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser { } // { initializer-list ,opt } - List initList= initializerList(true); + List initList= initializerList(allowSkipping); if (LT(1) == IToken.tCOMMA) consume(); @@ -2896,14 +2896,14 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser { * initializer-clause ...opt * initializer-list , initializer-clause ...opt */ - private List initializerList(boolean inAggregateInit) throws EndOfFileException, + private List initializerList(boolean allowSkipping) throws EndOfFileException, BacktrackException { List result= null; // List of initializer clauses loop: for(;;) { // Clause may be null, add to initializer anyways, such that the size can be computed. - IASTInitializerClause clause = initClause(inAggregateInit); + IASTInitializerClause clause = initClause(allowSkipping); if (LT(1) == IToken.tELLIPSIS) { final int endOffset = consume(IToken.tELLIPSIS).getEndOffset(); if (clause instanceof ICPPASTPackExpandable) { @@ -4073,7 +4073,7 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser { IASTInitializerClause expr = null; final int lt1 = LT(1); if (lt1 == IToken.tLBRACE) { - expr= bracedInitList(); + expr= bracedInitList(true); } else if (lt1 != IToken.tSEMI) { expr = expression(); } 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 522ad073065..687189a0d9e 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 @@ -93,6 +93,7 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTForStatement; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFunctionDeclarator; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFunctionDefinition; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTIfStatement; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTInitializerList; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTLinkageSpecification; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTNamedTypeSpecifier; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTNamespaceAlias; @@ -393,7 +394,7 @@ public class CPPSemantics { // if the lookup in base-classes ran into a deferred instance, use the computed unknown binding. final ASTNodeProperty namePropertyInParent = name.getPropertyInParent(); if (binding == null && data.skippedScope != null) { - if (data.hasArgumentTypes()) { + if (data.hasFunctionArguments()) { binding= new CPPUnknownFunction(data.skippedScope, name.getSimpleID()); } else { if (namePropertyInParent == IASTNamedTypeSpecifier.NAME) { @@ -527,11 +528,25 @@ public class CPPSemantics { return false; } + public static IBinding selectConstructor(ICPPClassType classTarget, ICPPASTInitializerList initializerList) { + LookupData data= new LookupData(); + IASTName name = new CPPASTName(classTarget.getNameCharArray()); + name.setParent(initializerList); + name.setPropertyInParent(CPPSemantics.STRING_LOOKUP_PROPERTY); + data.setFunctionArguments(initializerList); + try { + return CPPSemantics.selectConstructor(classTarget, data); + } catch (DOMException e) { + return e.getProblem(); + } + } + private static IBinding selectConstructor(ICPPClassType cls, LookupData data) throws DOMException { // Force resolution of constructor bindings final ICPPConstructor[] constructors= cls.getConstructors(); if (constructors.length > 0) { - return CPPSemantics.resolveAmbiguities(data.astName, constructors); + data.foundItems= constructors; + return CPPSemantics.resolveAmbiguities(data, data.astName); } return cls; } @@ -626,8 +641,8 @@ public class CPPSemantics { data.setFunctionArguments(); } else if (init instanceof ICPPASTConstructorInitializer) { data.setFunctionArguments(((ICPPASTConstructorInitializer) init).getArguments()); - } else { - // mstodo handle braced init list + } else if (init instanceof ICPPASTInitializerList) { + data.setFunctionArguments(new IASTInitializerClause[] {(ICPPASTInitializerList) init}); } } } else if (parent instanceof ICPPASTConstructorChainInitializer) { @@ -635,8 +650,8 @@ public class CPPSemantics { IASTInitializer init = ctorinit.getInitializer(); if (init instanceof ICPPASTConstructorInitializer) { data.setFunctionArguments(((ICPPASTConstructorInitializer) init).getArguments()); - } else { - // mstodo handle braced init list + } else if (init instanceof ICPPASTInitializerList) { + data.setFunctionArguments(new IASTInitializerClause[] {(ICPPASTInitializerList) init}); } } @@ -644,7 +659,7 @@ public class CPPSemantics { } static private ObjectSet getAssociatedScopes(LookupData data) { - if (!data.hasArgumentTypes()) + if (!data.hasFunctionArguments()) return ObjectSet.emptySet(); IType[] ps = data.getFunctionArgumentTypes(); @@ -2138,7 +2153,8 @@ public class CPPSemantics { } // We don't have any arguments with which to resolve the function - if (!data.hasArgumentTypes()) { + final boolean isFuncDecl = data.forFunctionDeclaration(); + if (!data.hasFunctionArguments()) { return resolveTargetedFunction(data, fns); } @@ -2146,7 +2162,7 @@ public class CPPSemantics { return resolveUserDefinedConversion(data, fns); } - if (!data.forFunctionDeclaration() || data.forExplicitFunctionSpecialization()) { + if (!isFuncDecl || data.forExplicitFunctionSpecialization()) { CPPTemplates.instantiateFunctionTemplates(fns, data.getFunctionArgumentTypes(), data.getFunctionArgumentLValues(), data.astName); } @@ -2165,7 +2181,7 @@ public class CPPSemantics { } } } - if (firstViable == null || data.forFunctionDeclaration()) + if (firstViable == null || isFuncDecl) return firstViable; // The arguments the function is being called with 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 07228934332..2e4f4e9e454 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 @@ -30,6 +30,7 @@ import org.eclipse.cdt.core.dom.ast.IASTElaboratedTypeSpecifier; import org.eclipse.cdt.core.dom.ast.IASTExpression; import org.eclipse.cdt.core.dom.ast.IASTFunctionDefinition; import org.eclipse.cdt.core.dom.ast.IASTIdExpression; +import org.eclipse.cdt.core.dom.ast.IASTInitializerClause; import org.eclipse.cdt.core.dom.ast.IASTName; import org.eclipse.cdt.core.dom.ast.IASTNode; import org.eclipse.cdt.core.dom.ast.IASTSimpleDeclaration; @@ -50,6 +51,7 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTCompositeTypeSpecifier; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTElaboratedTypeSpecifier; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTExplicitTemplateInstantiation; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFunctionDefinition; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTInitializerList; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTNamedTypeSpecifier; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTParameterDeclaration; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTQualifiedName; @@ -1542,6 +1544,8 @@ public class CPPTemplates { } static protected void instantiateFunctionTemplates(IFunction[] functions, IType[] fnArgs, BitSet argIsLValue, IASTName name) { + // mstodo handle list initialization + boolean requireTemplate= false; if (name != null) { if (name.getPropertyInParent() == ICPPASTTemplateId.TEMPLATE_NAME) { @@ -2045,12 +2049,29 @@ public class CPPTemplates { return true; } t= ((ITypeContainer) t).getType(); + } else if (t instanceof InitializerListType) { + return isDependentInitializerList(((InitializerListType) t).getInitializerList()); } else { return false; } } } + private static boolean isDependentInitializerList(ICPPASTInitializerList initializerList) { + IASTInitializerClause[] clauses= initializerList.getClauses(); + for (IASTInitializerClause clause : clauses) { + if (clause instanceof IASTExpression) { + IType t= ((IASTExpression) clause).getExpressionType(); + if (isDependentType(t)) + return true; + } else if (clause instanceof ICPPASTInitializerList) { + if (isDependentInitializerList((ICPPASTInitializerList) clause)) + return true; + } + } + return false; + } + public static boolean containsDependentArg(ObjectMap tpMap) { for (Object arg : tpMap.valueArray()) { if (isDependentType((IType)arg)) 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 35679d0a656..e98f5c75390 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 @@ -24,6 +24,7 @@ import org.eclipse.cdt.core.dom.ast.IASTExpression; import org.eclipse.cdt.core.dom.ast.IASTLiteralExpression; import org.eclipse.cdt.core.dom.ast.IArrayType; import org.eclipse.cdt.core.dom.ast.IBasicType; +import org.eclipse.cdt.core.dom.ast.IBinding; import org.eclipse.cdt.core.dom.ast.IEnumeration; import org.eclipse.cdt.core.dom.ast.IFunctionType; import org.eclipse.cdt.core.dom.ast.IPointerType; @@ -33,17 +34,23 @@ import org.eclipse.cdt.core.dom.ast.IType; import org.eclipse.cdt.core.dom.ast.IValue; import org.eclipse.cdt.core.dom.ast.IBasicType.Kind; import org.eclipse.cdt.core.dom.ast.cpp.ICPPBasicType; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassSpecialization; import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassType; import org.eclipse.cdt.core.dom.ast.cpp.ICPPConstructor; import org.eclipse.cdt.core.dom.ast.cpp.ICPPFunctionType; import org.eclipse.cdt.core.dom.ast.cpp.ICPPMethod; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPNamespace; import org.eclipse.cdt.core.dom.ast.cpp.ICPPPointerToMemberType; import org.eclipse.cdt.core.dom.ast.cpp.ICPPReferenceType; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateArgument; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateInstance; +import org.eclipse.cdt.core.parser.util.CharArrayUtils; import org.eclipse.cdt.internal.core.dom.parser.ArithmeticConversion; import org.eclipse.cdt.internal.core.dom.parser.Value; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPBasicType; 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.Rank; import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.Cost.ReferenceBinding; @@ -58,6 +65,9 @@ public class Conversions { 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 @@ -85,7 +95,7 @@ public class Conversions { final IType cv2T2= exprType; final IType T2= getNestedType(cv2T2, TDEF | REF | ALLCVQ); - final boolean isImplicitWithoutRefQualifier = isImpliedObjectType; // mstodo need to pass this information to here + final boolean isImplicitWithoutRefQualifier = isImpliedObjectType; ReferenceBinding refBindingType= ReferenceBinding.OTHER; if (!isImplicitWithoutRefQualifier) { if (isLValueRef) { @@ -258,6 +268,9 @@ public class Conversions { } private static Cost nonReferenceConversion(boolean sourceIsLValue, IType source, IType target, UDCMode udc, boolean isImpliedObject) throws DOMException { + if (source instanceof InitializerListType) { + return listInitializationSequence(((InitializerListType) source), target, udc); + } // [13.3.3.1-6] Subsume cv-qualifications IType uqSource= SemanticUtil.getNestedType(source, TDEF | ALLCVQ); Cost cost= checkStandardConversionSequence(uqSource, sourceIsLValue, target, isImpliedObject); @@ -271,6 +284,68 @@ public class Conversions { return cost; } + /** + * 13.3.3.1.5 List-initialization sequence [over.ics.list] + */ + private static Cost listInitializationSequence(InitializerListType arg, IType target, UDCMode udc) throws DOMException { + IType listType= getInitListType(target); + if (listType != null) { + IType[] exprTypes= arg.getExpressionTypes(); + BitSet isLValue= arg.getIsLValue(); + 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); + if (cost.getRank() == Rank.NO_MATCH) + return cost; + if (cost.isNarrowingConversion()) { + cost.setRank(Rank.NO_MATCH); + return cost; + } + if (cost.compareTo(worstCost) > 0) { + worstCost= cost; + } + } + return worstCost; + } + + IType noCVTarget= getNestedType(target, CVTYPE | TDEF); + if (noCVTarget instanceof ICPPClassType) { + if (udc == UDCMode.noUDC) + return new Cost(arg, target, Rank.NO_MATCH); + + ICPPClassType classTarget= (ICPPClassType) noCVTarget; + if (ClassTypeHelper.isAggregateClass(classTarget)) { + return new Cost(arg, target, Rank.USER_DEFINED_CONVERSION); + } + Cost cost= checkUserDefinedConversionSequence(false, arg, target, udc == UDCMode.deferUDC); + if (cost != null) + return cost; + } + return new Cost(arg, target, Rank.NO_MATCH); + } + + private static IType getInitListType(IType target) throws DOMException { + if (target instanceof ICPPClassSpecialization && target instanceof ICPPTemplateInstance) { + ICPPTemplateInstance inst = (ICPPTemplateInstance) target; + if (CharArrayUtils.equals(INITIALIZER_LIST_NAME, inst.getNameCharArray())) { + IBinding owner = inst.getOwner(); + if (owner instanceof ICPPNamespace + && CharArrayUtils.equals(STD_NAME, owner.getNameCharArray()) + && owner.getOwner() == null) { + ICPPTemplateArgument[] args = inst.getTemplateArguments(); + if (args.length == 1) { + ICPPTemplateArgument arg = args[0]; + if (arg.isTypeValue()) { + return arg.getTypeValue(); + } + } + } + } + } + return null; + } + /** * [3.9.3-4] Implements cv-ness (partial) comparison. There is a (partial) * ordering on cv-qualifiers, so that a type can be said to be more @@ -423,6 +498,7 @@ public class Conversions { * @throws DOMException */ static final Cost checkUserDefinedConversionSequence(boolean sourceIsLValue, IType source, IType target, boolean deferUDC) throws DOMException { + // mstodo don't return null IType s= getNestedType(source, TDEF | CVTYPE | REF); IType t= getNestedType(target, TDEF | CVTYPE | REF); @@ -436,106 +512,130 @@ public class Conversions { return c; } - // 13.3.1.4 Copy initialization of class by user-defined conversion if (t instanceof ICPPClassType) { - FunctionCost cost1= null; - Cost cost2= null; - ICPPConstructor[] ctors= ((ICPPClassType) t).getConstructors(); - CPPTemplates.instantiateFunctionTemplates(ctors, new IType[]{source}, sourceIsLValue ? LVBITSET : RVBITSET, null); - - for (ICPPConstructor ctor : ctors) { - if (ctor != null && !(ctor instanceof IProblemBinding) && !ctor.isExplicit()) { - final ICPPFunctionType ft = ctor.getType(); - final IType[] ptypes = ft.getParameterTypes(); - FunctionCost c1; - if (ptypes.length == 0) { - if (ctor.takesVarArgs()) { - c1= new FunctionCost(ctor, new Cost(source, null, Rank.ELLIPSIS_CONVERSION)); - } else { - continue; - } - } else { - IType ptype= SemanticUtil.getNestedType(ptypes[0], TDEF); - // We don't need to check the implicit conversion sequence if the type is void - if (SemanticUtil.isVoidType(ptype)) - continue; - if (ctor.getRequiredArgumentCount() > 1) - continue; - - c1= new FunctionCost(ctor, checkImplicitConversionSequence(ptype, source, sourceIsLValue, UDCMode.noUDC, false)); - } - int cmp= c1.compareTo(null, cost1); - if (cmp <= 0) { - cost1= c1; - cost2= new Cost(t, t, Rank.IDENTITY); - cost2.setUserDefinedConversion(ctor); - if (cmp == 0) { - cost2.setAmbiguousUDC(true); - } - } - } + if (s instanceof InitializerListType) { + // 13.3.1.7 Initialization by list-initialization + return listInitializationOfClass((InitializerListType) s, (ICPPClassType) t, false); } - if (s instanceof ICPPClassType) { - ICPPMethod[] ops = SemanticUtil.getConversionOperators((ICPPClassType) s); - CPPTemplates.instantiateConversionTemplates(ops, target); - for (final ICPPMethod op : ops) { - if (op != null && !(op instanceof IProblemBinding)) { - final IType returnType = op.getType().getReturnType(); - final IType uqReturnType= getNestedType(returnType, REF | TDEF | CVTYPE); - final int dist = SemanticUtil.calculateInheritanceDepth(uqReturnType, t); - if (dist >= 0) { - final ICPPFunctionType ft = op.getType(); - IType implicitType= CPPSemantics.getImplicitType(op, ft.isConst(), ft.isVolatile()); - final Cost udcCost = isReferenceCompatible(getNestedType(implicitType, TDEF | REF), source, true); - if (udcCost != null) { - FunctionCost c1= new FunctionCost(op, udcCost); - int cmp= c1.compareTo(null, cost1); - if (cmp <= 0) { - cost1= c1; - cost2= new Cost(t, t, Rank.IDENTITY); - if (dist > 0) { - cost2.setInheritanceDistance(dist); - cost2.setRank(Rank.CONVERSION); - } - cost2.setUserDefinedConversion(op); - if (cmp == 0) { - cost2.setAmbiguousUDC(true); - } - } + // 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); + } + return null; + } + + private static Cost listInitializationOfClass(InitializerListType s, ICPPClassType t, boolean isDirect) throws DOMException { + // If T has an initializer-list constructor + ICPPConstructor usedCtor= null; + Cost bestCost= null; + ICPPConstructor[] ctors= t.getConstructors(); + for (ICPPConstructor ctor : ctors) { + if (ctor.getRequiredArgumentCount() <= 1) { + IType[] parTypes= ctor.getType().getParameterTypes(); + if (parTypes.length > 0) { + final IType target = parTypes[0]; + if (getInitListType(target) != null) { + Cost cost= listInitializationSequence(s, target, UDCMode.noUDC); + if (cost.getRank() == Rank.NO_MATCH) { + if (bestCost == null) { + bestCost= cost; + } + } else { + int cmp= cost.compareTo(bestCost); + if (bestCost == null || cmp < 0) { + usedCtor= ctor; + cost.setUserDefinedConversion(ctor); + bestCost= cost; + } else if (cmp == 0) { + bestCost.setAmbiguousUDC(true); } } } } } - if (cost1 == null || cost1.getCost(0).getRank() == Rank.NO_MATCH) - return null; - - return cost2; + } + if (bestCost != null) { + if (!bestCost.isAmbiguousUDC() && !isDirect) { + if (usedCtor != null && usedCtor.isExplicit()) { + bestCost.setRank(Rank.NO_MATCH); + } + } + return bestCost; } - // 13.3.1.5 Initialization by conversion function + // mstodo expanding the list for selecting the ctor. + return new Cost(s, t, Rank.NO_MATCH); + + } + + /** + * 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 { + FunctionCost cost1= null; + Cost cost2= null; + ICPPConstructor[] ctors= t.getConstructors(); + CPPTemplates.instantiateFunctionTemplates(ctors, new IType[]{source}, sourceIsLValue ? LVBITSET : RVBITSET, null); + + for (ICPPConstructor ctor : ctors) { + if (ctor != null && !(ctor instanceof IProblemBinding) && !ctor.isExplicit()) { + final ICPPFunctionType ft = ctor.getType(); + final IType[] ptypes = ft.getParameterTypes(); + FunctionCost c1; + if (ptypes.length == 0) { + if (ctor.takesVarArgs()) { + c1= new FunctionCost(ctor, new Cost(source, null, Rank.ELLIPSIS_CONVERSION)); + } else { + continue; + } + } else { + IType ptype= SemanticUtil.getNestedType(ptypes[0], TDEF); + // We don't need to check the implicit conversion sequence if the type is void + if (SemanticUtil.isVoidType(ptype)) + continue; + if (ctor.getRequiredArgumentCount() > 1) + continue; + + c1= new FunctionCost(ctor, checkImplicitConversionSequence(ptype, source, sourceIsLValue, UDCMode.noUDC, false)); + } + int cmp= c1.compareTo(null, cost1); + if (cmp <= 0) { + cost1= c1; + cost2= new Cost(t, t, Rank.IDENTITY); + cost2.setUserDefinedConversion(ctor); + if (cmp == 0) { + cost2.setAmbiguousUDC(true); + } + } + } + } if (s instanceof ICPPClassType) { ICPPMethod[] ops = SemanticUtil.getConversionOperators((ICPPClassType) s); CPPTemplates.instantiateConversionTemplates(ops, target); - FunctionCost cost1= null; - Cost cost2= null; for (final ICPPMethod op : ops) { if (op != null && !(op instanceof IProblemBinding)) { 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); - if (c2.getRank() != Rank.NO_MATCH) { - ICPPFunctionType ftype = op.getType(); - IType implicitType= CPPSemantics.getImplicitType(op, ftype.isConst(), ftype.isVolatile()); + final IType uqReturnType= getNestedType(returnType, REF | TDEF | CVTYPE); + final int dist = SemanticUtil.calculateInheritanceDepth(uqReturnType, t); + if (dist >= 0) { + final ICPPFunctionType ft = op.getType(); + IType implicitType= CPPSemantics.getImplicitType(op, ft.isConst(), ft.isVolatile()); final Cost udcCost = isReferenceCompatible(getNestedType(implicitType, TDEF | REF), source, true); if (udcCost != null) { FunctionCost c1= new FunctionCost(op, udcCost); int cmp= c1.compareTo(null, cost1); if (cmp <= 0) { cost1= c1; - cost2= c2; + cost2= new Cost(t, t, Rank.IDENTITY); + if (dist > 0) { + cost2.setInheritanceDistance(dist); + cost2.setRank(Rank.CONVERSION); + } cost2.setUserDefinedConversion(op); if (cmp == 0) { cost2.setAmbiguousUDC(true); @@ -545,12 +645,51 @@ public class Conversions { } } } - if (cost1 == null || cost1.getCost(0).getRank() == Rank.NO_MATCH) - return null; - - return cost2; } - return null; + if (cost1 == null || cost1.getCost(0).getRank() == Rank.NO_MATCH) + return null; + + return cost2; + } + + /** + * 13.3.1.5 Initialization by conversion function [over.match.conv] + */ + private static Cost initializationByConversion(IType source, ICPPClassType s, IType target) throws DOMException { + ICPPMethod[] ops = SemanticUtil.getConversionOperators(s); + CPPTemplates.instantiateConversionTemplates(ops, target); + FunctionCost cost1= null; + Cost cost2= null; + for (final ICPPMethod op : ops) { + if (op != null && !(op instanceof IProblemBinding)) { + 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); + if (c2.getRank() != Rank.NO_MATCH) { + ICPPFunctionType ftype = op.getType(); + IType implicitType= CPPSemantics.getImplicitType(op, ftype.isConst(), ftype.isVolatile()); + final Cost udcCost = isReferenceCompatible(getNestedType(implicitType, TDEF | REF), source, true); + if (udcCost != null) { + FunctionCost c1= new FunctionCost(op, udcCost); + int cmp= c1.compareTo(null, cost1); + if (cmp <= 0) { + cost1= c1; + cost2= c2; + cost2.setUserDefinedConversion(op); + if (cmp == 0) { + cost2.setAmbiguousUDC(true); + } + } + } + } + } + } + if (cost1 == null || cost1.getCost(0).getRank() == Rank.NO_MATCH) + return null; + + return cost2; } /** @@ -779,6 +918,7 @@ public class Conversions { // 4.7 An rvalue of an integer type can be converted to an rvalue of another integer type. // An rvalue of an enumeration type can be converted to an rvalue of an integer type. cost.setRank(Rank.CONVERSION); + cost.setCouldNarrow(); return true; } // 4.12 pointer or pointer to member type can be converted to an rvalue of type bool @@ -812,7 +952,7 @@ public class Conversions { IType tgtPtrTgt= getNestedType(tgtPtr.getType(), TDEF | CVTYPE | REF); if (SemanticUtil.isVoidType(tgtPtrTgt)) { cost.setRank(Rank.CONVERSION); - cost.setInheritanceDistance(Short.MAX_VALUE); // mstodo add distance to last base class + cost.setInheritanceDistance(Short.MAX_VALUE); CVQualifier cv= getCVQualifier(srcPtr.getType()); cost.source= new CPPPointerType(addQualifiers(CPPSemantics.VOID_TYPE, cv.isConst(), cv.isVolatile())); return false; 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 52b7ad002cb..1479380289b 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 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2004, 2009 IBM Corporation and others. + * Copyright (c) 2004, 2010 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -42,6 +42,8 @@ final class Cost { private int fInheritanceDistance; private ICPPFunction fUserDefinedConversion; private ReferenceBinding fReferenceBinding; + + private boolean fCouldNarrow; public Cost(IType s, IType t, Rank rank) { source = s; @@ -125,9 +127,11 @@ final class Cost { if (isAmbiguousUDC() || other.isAmbiguousUDC()) return 0; - if (!fUserDefinedConversion.equals(other.fUserDefinedConversion)) - return 0; - + if (fUserDefinedConversion != other.fUserDefinedConversion) { + if (fUserDefinedConversion == null || + !fUserDefinedConversion.equals(other.fUserDefinedConversion)) + return 0; + } cmp= fSecondStandardConversionRank.compareTo(other.fSecondStandardConversionRank); if (cmp != 0) return cmp; @@ -183,4 +187,12 @@ final class Cost { buf.append(']'); return buf.toString(); } + + public boolean isNarrowingConversion() { + return fCouldNarrow; + } + + public void setCouldNarrow() { + fCouldNarrow= true; + } } \ No newline at end of file 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 0121ab087a6..d4612ec1148 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 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2009 Wind River Systems, Inc. and others. + * Copyright (c) 2009, 2010 Wind River Systems, Inc. and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -77,7 +77,7 @@ class FunctionCost { Cost cost = fCosts[i]; if (cost.isDeferredUDC()) { Cost udcCost= Conversions.checkUserDefinedConversionSequence(fSourceIsLValue.get(i), cost.source, cost.target, false); - if (udcCost == null) { + if (udcCost == null || udcCost.getRank() == Rank.NO_MATCH) { return false; } fCosts[i]= udcCost; 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 new file mode 100644 index 00000000000..90f98de7dd2 --- /dev/null +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/InitializerListType.java @@ -0,0 +1,84 @@ +/******************************************************************************* + * Copyright (c) 2010 Wind River Systems, Inc. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Markus Schorn - initial API and implementation + *******************************************************************************/ +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.IASTInitializerClause; +import org.eclipse.cdt.core.dom.ast.IType; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTInitializerList; + +/** + * Wrapper for initializer lists to allow for participation in the overload resolution. + */ +class InitializerListType implements IType { + + private final ICPPASTInitializerList fInitializerList; + private IType[] fExpressionTypes; + private BitSet fLValues; + + public InitializerListType(ICPPASTInitializerList list) { + fInitializerList= list; + } + + public boolean isSameType(IType type) { + return false; + } + + @Override + public Object clone() { + try { + return super.clone(); + } catch (CloneNotSupportedException e) { + // Will not happen, we IType extends Clonable. + return null; + } + } + + public ICPPASTInitializerList getInitializerList() { + return fInitializerList; + } + + public IType[] getExpressionTypes() { + if (fExpressionTypes == null) { + final IASTInitializerClause[] clauses = fInitializerList.getClauses(); + fExpressionTypes= new IType[clauses.length]; + for (int i = 0; i < clauses.length; i++) { + IASTInitializerClause clause = clauses[i]; + if (clause instanceof IASTExpression) { + fExpressionTypes[i]= ((IASTExpression) clause).getExpressionType(); + } else if (clause instanceof ICPPASTInitializerList) { + fExpressionTypes[i]= new InitializerListType((ICPPASTInitializerList) clause); + } else { + assert false; + } + } + } + return fExpressionTypes; + } + + public BitSet getIsLValue() { + if (fLValues == null) { + final IASTInitializerClause[] clauses = fInitializerList.getClauses(); + fLValues= new BitSet(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); + } + } + } + } + return fLValues; + } +} 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 dda37a4790c..2f30dea4bd0 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 @@ -49,6 +49,7 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTDeleteExpression; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTElaboratedTypeSpecifier; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTExplicitTemplateInstantiation; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFieldReference; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTInitializerList; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTNamespaceDefinition; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTParameterDeclaration; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTQualifiedName; @@ -101,12 +102,14 @@ public class LookupData { public boolean firstArgIsImpliedMethodArg = false; public boolean ignoreMembers = false; + private ICPPASTParameterDeclaration[] functionParameters; + private IASTInitializerClause[] functionArgs; + private IType[] functionArgTypes; + private BitSet functionArgLValues; + public ICPPClassType skippedScope; public Object foundItems = null; - private Object[] functionArgs; - private IType[] functionArgTypes; public ProblemBinding problem; - private BitSet functionArgLValues; public LookupData(IASTName n) { astName = n; @@ -529,27 +532,27 @@ public class LookupData { } public IType[] getFunctionArgumentTypes() { - if (functionArgTypes == null && functionArgs != null) { - if (functionArgs instanceof ICPPASTParameterDeclaration[]) { - ICPPASTParameterDeclaration[] pdecls= (ICPPASTParameterDeclaration[]) functionArgs; - functionArgTypes= new IType[pdecls.length]; - for (int i = 0; i < pdecls.length; i++) { - functionArgTypes[i] = SemanticUtil.getSimplifiedType(CPPVisitor.createParameterType( - pdecls[i], true)); - } - } else if (functionArgs instanceof IASTInitializerClause[]) { - IASTInitializerClause[] exprs= (IASTInitializerClause[]) functionArgs; + if (functionArgTypes == null) { + if (functionArgs != null) { + IASTInitializerClause[] exprs= functionArgs; functionArgTypes= new IType[exprs.length]; for (int i = 0; i < exprs.length; i++) { IASTInitializerClause e = exprs[i]; if (e instanceof IASTExpression) { IType etype= ((IASTExpression) e).getExpressionType(); functionArgTypes[i]= SemanticUtil.getSimplifiedType(etype); - } else { - // mstodo handle braced init list + } else if (e instanceof ICPPASTInitializerList) { + functionArgTypes[i]= new InitializerListType((ICPPASTInitializerList) e); } } - } + } else if (functionParameters != null) { + ICPPASTParameterDeclaration[] pdecls= functionParameters; + functionArgTypes= new IType[pdecls.length]; + for (int i = 0; i < pdecls.length; i++) { + functionArgTypes[i] = SemanticUtil.getSimplifiedType(CPPVisitor.createParameterType( + pdecls[i], true)); + } + } } return functionArgTypes; } @@ -564,7 +567,7 @@ public class LookupData { if (arg instanceof IASTExpression) { functionArgLValues.set(i, ((IASTExpression) arg).isLValue()); } else { - // mstodo handle braced init list + functionArgLValues.set(i, false); } } } else { @@ -580,32 +583,24 @@ public class LookupData { return functionArgLValues; } - - public void setFunctionArgumentTypes(IType[] paramTypes) { - functionArgTypes= paramTypes; - } - public void setFunctionParameters(ICPPASTParameterDeclaration[] parameters) { - functionArgs= parameters; + functionParameters= parameters; } public IASTInitializerClause[] getFunctionArguments() { - if (functionArgs instanceof IASTInitializerClause[]) - return (IASTInitializerClause[]) functionArgs; - - return null; + return functionArgs; } public int getFunctionArgumentCount() { if (functionArgs != null) return functionArgs.length; - if (functionArgTypes != null) - return functionArgTypes.length; + if (functionParameters != null) + return functionParameters.length; return 0; } - public boolean hasArgumentTypes() { - return functionArgTypes != null || functionArgs != null; + public boolean hasFunctionArguments() { + return functionArgs != null || functionParameters != null; } public IBinding[] getFoundBindings() {