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 997cad83aea..bd719337531 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 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2004, 2014 IBM Corporation and others. + * Copyright (c) 2004, 2015 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -9551,7 +9551,7 @@ public class AST2CPPTests extends AST2TestBase { // int k = g(f1()); // calls g(const int&&) // int l = g(f2()); // calls g(const int&&) // } - public void testRankingOfReferenceBindings() throws Exception { + public void testRankingOfReferenceBindings_1() throws Exception { BindingAssertionHelper bh= getAssertionHelper(); IFunction g1= bh.assertNonProblemOnFirstIdentifier("g(const int&)"); IFunction g2= bh.assertNonProblemOnFirstIdentifier("g(const int&&)"); @@ -9564,7 +9564,46 @@ public class AST2CPPTests extends AST2TestBase { ref= bh.assertNonProblemOnFirstIdentifier("g(f2());"); assertSame(g2, ref); } - + + // struct A { + // A& operator<<(int); + // void p() &; + // void p() &&; + // }; + // A& operator<<(A&&, char); + // + // void test() { + // A a; + // A() << 1;//1 // calls A::operator<<(int) + // A() << 'c';//2 // calls operator<<(A&&, char) + // a << 1;//3 // calls A::operator<<(int) + // a << 'c';//4 // calls A::operator<<(int) + // A().p();//5 // calls A::p()&& + // a.p();//6 // calls A::p()& + // } + public void testRankingOfReferenceBindings_2() throws Exception { + BindingAssertionHelper bh= getAssertionHelper(); + ICPPMethod s1= bh.assertNonProblem("operator<<(int)", 10); + ICPPFunction s2= bh.assertNonProblem("operator<<(A&&, char)", 10); + ICPPMethod p1= bh.assertNonProblemOnFirstIdentifier("p() &;"); + ICPPMethod p2= bh.assertNonProblemOnFirstIdentifier("p() &&;"); + + IASTImplicitName name; + name= bh.assertImplicitName("<< 1;//1", 2, ICPPMethod.class); + assertSame(s1, name.getBinding()); + name= bh.assertImplicitName("<< 'c';//2", 2, ICPPFunction.class); + assertSame(s2, name.getBinding()); + name= bh.assertImplicitName("<< 1;//3", 2, ICPPMethod.class); + assertSame(s1, name.getBinding()); + name= bh.assertImplicitName("<< 'c';//4", 2, ICPPMethod.class); + assertSame(s1, name.getBinding()); + ICPPMethod ref; + ref= bh.assertNonProblemOnFirstIdentifier("p();//5"); + assertSame(p2, ref); + ref= bh.assertNonProblemOnFirstIdentifier("p();//6"); + assertSame(p1, ref); + } + // namespace std { // template class initializer_list; // } 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 73d6885692d..7676d8601ed 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 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2004, 2014 IBM Corporation and others. + * Copyright (c) 2004, 2015 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -2724,8 +2724,8 @@ public class CPPSemantics { private static FunctionCost costForFunctionCall(ICPPFunction fn, boolean allowUDC, LookupData data) throws DOMException { - IType[] argTypes = data.getFunctionArgumentTypes(); - ValueCategory[] isLValue= data.getFunctionArgumentValueCategories(); + IType[] argTypes= data.getFunctionArgumentTypes(); + ValueCategory[] argValueCategories= data.getFunctionArgumentValueCategories(); int skipArg= 0; final ICPPFunctionType ftype= fn.getType(); if (ftype == null) @@ -2733,11 +2733,13 @@ public class CPPSemantics { IType implicitParameterType= null; IType impliedObjectType= null; + ValueCategory impliedObjectValueCategory= null; final IType[] paramTypes= ftype.getParameterTypes(); if (fn instanceof ICPPMethod && !(fn instanceof ICPPConstructor)) { implicitParameterType = getImplicitParameterType((ICPPMethod) fn); if (data.argsContainImpliedObject) { impliedObjectType= argTypes[0]; + impliedObjectValueCategory= argValueCategories[0]; skipArg= 1; } } @@ -2751,10 +2753,15 @@ public class CPPSemantics { } else { result= new FunctionCost(fn, sourceLen + 1, data.getLookupPoint()); - ValueCategory sourceIsLValue= LVALUE; if (impliedObjectType == null) { impliedObjectType= data.getImpliedObjectType(); } + if (impliedObjectValueCategory == null) { + impliedObjectValueCategory= data.getImpliedObjectValueCategory(); + if (impliedObjectValueCategory == null) + impliedObjectValueCategory= ValueCategory.LVALUE; + } + if (fn instanceof ICPPMethod && (((ICPPMethod) fn).isDestructor() || ASTInternal.isStatic(fn, false))) { // 13.3.1-4 for static member functions, the implicit object parameter always matches, no cost @@ -2766,7 +2773,11 @@ public class CPPSemantics { cost = new Cost(impliedObjectType, implicitParameterType, Rank.IDENTITY); cost.setImpliedObject(); } else { - cost = Conversions.checkImplicitConversionSequence(implicitParameterType, impliedObjectType, sourceIsLValue, UDCMode.FORBIDDEN, Context.IMPLICIT_OBJECT, data.getLookupPoint()); + Context context = ftype.hasRefQualifier() ? + Context.IMPLICIT_OBJECT_FOR_METHOD_WITH_REF_QUALIFIER : + Context.IMPLICIT_OBJECT_FOR_METHOD_WITHOUT_REF_QUALIFIER; + cost = Conversions.checkImplicitConversionSequence(implicitParameterType, impliedObjectType, + impliedObjectValueCategory, UDCMode.FORBIDDEN, context, data.getLookupPoint()); if (cost.converts()) { cost.setImpliedObject(); } else { @@ -2783,7 +2794,7 @@ public class CPPSemantics { if (!cost.converts()) return null; - result.setCost(k++, cost, sourceIsLValue); + result.setCost(k++, cost, impliedObjectValueCategory); } final UDCMode udc = allowUDC ? UDCMode.DEFER : UDCMode.FORBIDDEN; @@ -2792,7 +2803,7 @@ public class CPPSemantics { if (argType == null) return null; - final ValueCategory sourceIsLValue = isLValue[j + skipArg]; + final ValueCategory argValueCategory = argValueCategories[j + skipArg]; IType paramType; if (j < paramTypes.length) { @@ -2801,7 +2812,7 @@ public class CPPSemantics { paramType= VOID_TYPE; } else { cost = new Cost(argType, null, Rank.ELLIPSIS_CONVERSION); - result.setCost(k++, cost, sourceIsLValue); + result.setCost(k++, cost, argValueCategory); continue; } @@ -2822,7 +2833,7 @@ public class CPPSemantics { } } } - cost = Conversions.checkImplicitConversionSequence(paramType, argType, sourceIsLValue, + cost = Conversions.checkImplicitConversionSequence(paramType, argType, argValueCategory, udc, ctx, data.getLookupPoint()); if (data.fNoNarrowing && cost.isNarrowingConversion(data.getLookupPoint())) { cost= Cost.NO_CONVERSION; @@ -2831,7 +2842,7 @@ public class CPPSemantics { if (!cost.converts()) return null; - result.setCost(k++, cost, sourceIsLValue); + result.setCost(k++, cost, argValueCategory); } return result; } @@ -2844,7 +2855,7 @@ public class CPPSemantics { } ICPPFunctionType ft= m.getType(); implicitType= SemanticUtil.addQualifiers(owner, ft.isConst(), ft.isVolatile(), false); - return new CPPReferenceType(implicitType, false); + return new CPPReferenceType(implicitType, ft.isRValueReference()); } private static IBinding resolveUserDefinedConversion(LookupData data, ICPPFunction[] fns) { 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 0e11a2f99d8..a98bf07b275 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 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2004, 2012 IBM Corporation and others. + * Copyright (c) 2004, 2015 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -73,14 +73,21 @@ import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.Cost.ReferenceBind */ public class Conversions { public enum UDCMode { ALLOWED, FORBIDDEN, DEFER } - public enum Context { ORDINARY, IMPLICIT_OBJECT, FIRST_PARAM_OF_DIRECT_COPY_CTOR, REQUIRE_DIRECT_BINDING } + public enum Context { + ORDINARY, + IMPLICIT_OBJECT_FOR_METHOD_WITHOUT_REF_QUALIFIER, + IMPLICIT_OBJECT_FOR_METHOD_WITH_REF_QUALIFIER, + FIRST_PARAM_OF_DIRECT_COPY_CTOR, + REQUIRE_DIRECT_BINDING + } private static final char[] INITIALIZER_LIST_NAME = "initializer_list".toCharArray(); //$NON-NLS-1$ private static final char[] STD_NAME = "std".toCharArray(); //$NON-NLS-1$ /** - * Computes the cost of an implicit conversion sequence [over.best.ics] 13.3.3.1 - * The semantics of the initialization is explained in 8.5-16 + * Computes the cost of an implicit conversion sequence [over.best.ics] 13.3.3.1. + * The semantics of the initialization is explained in 8.5-16. + * * @param target the target (parameter) type * @param exprType the source (argument) type * @param valueCat value category of the expression @@ -89,7 +96,9 @@ public class Conversions { */ public static Cost checkImplicitConversionSequence(IType target, IType exprType, ValueCategory valueCat, UDCMode udc, Context ctx, IASTNode point) throws DOMException { - final boolean isImpliedObject= ctx == Context.IMPLICIT_OBJECT; + final boolean isImpliedObject= + ctx == Context.IMPLICIT_OBJECT_FOR_METHOD_WITHOUT_REF_QUALIFIER || + ctx == Context.IMPLICIT_OBJECT_FOR_METHOD_WITH_REF_QUALIFIER; if (isImpliedObject) udc= UDCMode.FORBIDDEN; @@ -105,15 +114,7 @@ public class Conversions { final IType cv2T2= exprType; final IType T2= getNestedType(cv2T2, TDEF | REF | ALLCVQ); - // mstodo: will change when implementing rvalue references on this pointer - final boolean isImplicitWithoutRefQualifier = isImpliedObject; - if (!isImplicitWithoutRefQualifier) { - if (isLValueRef) { - refBindingType= ReferenceBinding.LVALUE_REF; - } else { - refBindingType= ReferenceBinding.RVALUE_REF_BINDS_RVALUE; - } - } + refBindingType= isLValueRef ? ReferenceBinding.LVALUE_REF : ReferenceBinding.RVALUE_REF_BINDS_RVALUE; if (exprType instanceof InitializerListType) { if (isLValueRef && getCVQualifier(cv1T1) != CVQualifier.CONST) @@ -130,7 +131,16 @@ 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 (valueCat == LVALUE) { + if (valueCat == LVALUE || ctx == Context.IMPLICIT_OBJECT_FOR_METHOD_WITHOUT_REF_QUALIFIER) { + // 13.3.3.5: For non-static member functions declared without a ref-qualifier, + // an additional rule applies: + // — even if the implicit object parameter is not const-qualified, an rvalue can be + // bound to the parameter as long as in all other respects the argument can be + // converted to the type of the implicit object parameter. + // [Note: The fact that such an argument is an rvalue does not affect the ranking of + // implicit conversion sequences (13.3.3.2). — end note] + if (valueCat != LVALUE) + refBindingType= ReferenceBinding.RVALUE_REF_BINDS_RVALUE; // ... and "cv1 T1" is reference-compatible with "cv2 T2" Cost cost= isReferenceCompatible(cv1T1, cv2T2, isImpliedObject, point); if (cost != null) { 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 203fcf6ff4f..3bceedfedf7 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 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2004, 2011 IBM Corporation and others. + * Copyright (c) 2004, 2015 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -53,6 +53,7 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTConstructorChainInitializer; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTDeclSpecifier; 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.ICPPASTExpression; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFieldReference; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTInitializerClause; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTNameSpecifier; @@ -106,6 +107,7 @@ public class LookupData extends ScopeLookupData { private IASTDeclarator fDeclarator; private boolean fFunctionCall; private IType fImpliedObjectType; + private ValueCategory fImpliedObjectValueCategory; private ICPPEvaluation[] functionArgs; private IType[] functionArgTypes; private ValueCategory[] functionArgValueCategories; @@ -356,7 +358,7 @@ public class LookupData extends ScopeLookupData { } /** - * Returns the implied object type, or null. + * Returns the implied object type, or {@code null} if there is no implied object. */ public IType getImpliedObjectType() { if (fImpliedObjectType == null) { @@ -365,9 +367,9 @@ public class LookupData extends ScopeLookupData { return fImpliedObjectType; } - /** - * Explicitly set the implied object type. - * This is for use in cases where implied object type cannot + /** + * Explicitly sets the implied object type. + * This method is for use in cases where implied object type cannot * be determined automatically because there is no lookup name. */ public void setImpliedObjectType(IType impliedObjectType) { @@ -407,6 +409,48 @@ public class LookupData extends ScopeLookupData { return null; } + /** + * Returns the category of the implied object, or {@code null} if there is no implied object. + * @see ValueCategory + */ + public ValueCategory getImpliedObjectValueCategory() { + if (fImpliedObjectValueCategory == null) { + fImpliedObjectValueCategory= determineImpliedObjectValueCategory(); + } + return fImpliedObjectValueCategory; + } + + private ValueCategory determineImpliedObjectValueCategory() { + IASTName tn = getLookupName(); + if (tn == null) + return null; + + if (tn.getPropertyInParent() == ICPPASTTemplateId.TEMPLATE_NAME) { + tn= (IASTName) tn.getParent(); + } + + IASTNode parent = tn.getParent(); + IASTNode nameParent= parent; + if (parent instanceof ICPPASTQualifiedName) { + final ICPPASTQualifiedName qn = (ICPPASTQualifiedName) parent; + if (qn.getLastName() == tn) { + nameParent= parent.getParent(); + } + } + + if (nameParent instanceof IASTFieldReference) { + ICPPASTFieldReference fieldReference = (ICPPASTFieldReference) nameParent; + ICPPASTExpression owner = fieldReference.getFieldOwner(); + if (fieldReference.isPointerDereference()) { + return ValueCategory.LVALUE; + } + return owner.getValueCategory(); + } else if (nameParent instanceof IASTIdExpression) { + return ValueCategory.LVALUE; + } + return null; + } + public boolean forFriendship() { IASTName lookupName= getLookupName(); if (lookupName == null) diff --git a/lrparser/org.eclipse.cdt.core.lrparser.tests/src/org/eclipse/cdt/core/lrparser/tests/LRCPPTests.java b/lrparser/org.eclipse.cdt.core.lrparser.tests/src/org/eclipse/cdt/core/lrparser/tests/LRCPPTests.java index fe93b263d86..c9042fe0555 100644 --- a/lrparser/org.eclipse.cdt.core.lrparser.tests/src/org/eclipse/cdt/core/lrparser/tests/LRCPPTests.java +++ b/lrparser/org.eclipse.cdt.core.lrparser.tests/src/org/eclipse/cdt/core/lrparser/tests/LRCPPTests.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2006, 2010 IBM Corporation and others. + * Copyright (c) 2006, 2015 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -10,8 +10,6 @@ *******************************************************************************/ package org.eclipse.cdt.core.lrparser.tests; -import junit.framework.TestSuite; - import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit; import org.eclipse.cdt.core.dom.lrparser.gnu.GCCLanguage; import org.eclipse.cdt.core.dom.lrparser.gnu.GPPLanguage; @@ -20,16 +18,16 @@ import org.eclipse.cdt.core.parser.ParserLanguage; import org.eclipse.cdt.core.parser.tests.ast2.AST2CPPTests; import org.eclipse.cdt.internal.core.parser.ParserException; +import junit.framework.TestSuite; + @SuppressWarnings("restriction") public class LRCPPTests extends AST2CPPTests { - public static TestSuite suite() { return suite(LRCPPTests.class); } public LRCPPTests() { - } public LRCPPTests(String name) { @@ -126,7 +124,9 @@ public class LRCPPTests extends AST2CPPTests { @Override public void testXValueCategories() throws Exception {} @Override - public void testRankingOfReferenceBindings() throws Exception {} + public void testRankingOfReferenceBindings_1() throws Exception {} + @Override + public void testRankingOfReferenceBindings_2() throws Exception {} @Override public void testInlineNamespaceLookup_324096() throws Exception {} @Override