mirror of
https://github.com/eclipse-cdt/cdt
synced 2025-04-29 19:45:01 +02:00
Bug 470014 - Name resolution problem with ref-qualified methods
Change-Id: I2baeee442adffefb1df2c217ed91c5ff58a430ae
This commit is contained in:
parent
a0fe9152df
commit
81d40de462
5 changed files with 144 additions and 40 deletions
|
@ -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<typename T> class initializer_list;
|
||||
// }
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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 <code>null</code>.
|
||||
* 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)
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Add table
Reference in a new issue