1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-06-07 09:46:02 +02:00

RValue References: Implementation and testcases, bug 294730.

This commit is contained in:
Markus Schorn 2009-11-24 10:53:12 +00:00
parent 042f47dbef
commit 99148105b3
60 changed files with 1066 additions and 375 deletions

View file

@ -51,7 +51,8 @@ public class ASTComparer extends Assert {
"isReference",
"isAssociatedWithLastName",
"getNestingLevel",
"getImplicitNames"
"getImplicitNames",
"isLValue"
));

View file

@ -23,6 +23,7 @@ import java.util.Iterator;
import junit.framework.TestSuite;
import org.eclipse.cdt.core.dom.ast.ASTSignatureUtil;
import org.eclipse.cdt.core.dom.ast.ASTTypeUtil;
import org.eclipse.cdt.core.dom.ast.EScopeKind;
import org.eclipse.cdt.core.dom.ast.IASTArrayDeclarator;
import org.eclipse.cdt.core.dom.ast.IASTBinaryExpression;
@ -7750,5 +7751,157 @@ public class AST2CPPTests extends AST2BaseTest {
final String code= getAboveComment();
parseAndCheckBindings(code, ParserLanguage.CPP);
}
// struct A {};
//
// void foo(const A&); // #1
// void foo(A&&); // #2
//
// A source_rvalue();
// A& source_ref();
// A&& source_rvalue_ref();
//
// const A source_const_rvalue();
// const A& source_const_ref();
// const A&& source_const_rvalue_ref();
//
// int main() {
// A a;
// A& ra = a;
// A&& rra = a;
// const A ca;
// const A& rca = ca;
// const A&& rrca = ca;
//
// foo(a); // #1
// foo(ra); // #1
// foo(rra); // #1
// foo(ca); // #1
// foo(rca); // #1
// foo(rrca); // #1
// foo(source_rvalue()); // #2
// foo(source_ref()); // #1
// foo(source_rvalue_ref()); // #2
// foo(source_const_rvalue()); // #1
// foo(source_const_ref()); // #1
// foo(source_const_rvalue_ref()); // #1
// }
public void testRValueReference_294730() throws Exception {
final String code= getAboveComment();
BindingAssertionHelper bh= new BindingAssertionHelper(code, true);
IBinding foo1= bh.assertNonProblem("foo(const A&)", 3);
IBinding foo2= bh.assertNonProblem("foo(A&&)", 3);
IBinding b;
b= bh.assertNonProblem("foo(a)", 3);
assertSame(b, foo1);
b= bh.assertNonProblem("foo(ra)", 3);
assertSame(b, foo1);
b= bh.assertNonProblem("foo(rra)", 3);
assertSame(b, foo1);
b= bh.assertNonProblem("foo(ca)", 3);
assertSame(b, foo1);
b= bh.assertNonProblem("foo(rca)", 3);
assertSame(b, foo1);
b= bh.assertNonProblem("foo(rrca)", 3);
assertSame(b, foo1);
b= bh.assertNonProblem("foo(source_rvalue())", 3);
assertSame(b, foo2);
b= bh.assertNonProblem("foo(source_ref())", 3);
assertSame(b, foo1);
b= bh.assertNonProblem("foo(source_rvalue_ref())", 3);
assertSame(b, foo2);
b= bh.assertNonProblem("foo(source_const_rvalue())", 3);
assertSame(b, foo1);
b= bh.assertNonProblem("foo(source_const_ref())", 3);
assertSame(b, foo1);
b= bh.assertNonProblem("foo(source_const_rvalue_ref())", 3);
assertSame(b, foo1);
}
// int i;
// typedef int& LRI;
// typedef int&& RRI;
// LRI& r1 = i; // r1 has the type int&
// const LRI& r2 = i; // r2 has the type int&
// const LRI&& r3 = i; // r3 has the type int&
// RRI& r4 = i; // r4 has the type int&
// RRI&& r5 = i; // r5 has the type int&&
public void testRValueReferenceTypedefs_294730() throws Exception {
final String code= getAboveComment();
BindingAssertionHelper bh= new BindingAssertionHelper(code, true);
IVariable v;
v= bh.assertNonProblem("r1", 2);
assertEquals("int &", ASTTypeUtil.getType(v.getType()));
v= bh.assertNonProblem("r2", 2);
assertEquals("int &", ASTTypeUtil.getType(v.getType()));
v= bh.assertNonProblem("r3", 2);
assertEquals("int &", ASTTypeUtil.getType(v.getType()));
v= bh.assertNonProblem("r4", 2);
assertEquals("int &", ASTTypeUtil.getType(v.getType()));
v= bh.assertNonProblem("r5", 2);
assertEquals("int &&", ASTTypeUtil.getType(v.getType()));
}
// void dref(double&);
// void drref(double&&);
// void cdref(const double&);
// struct A { };
// struct B : A { };
// extern B f();
// struct X {
// operator B();
// } x;
// void aref(A&);
// void caref(const A&);
// void carref(const A&&);
// void test() {
// B b;
// double d = 2.0;
// const volatile double cvd = 1;
// int i = 2;
// dref(d);
// cdref(d);
// aref(b);
// caref(b);
// dref(2.0); // error: not an lvalue and reference not const
// dref(i); // error: type mismatch and reference not const
// drref(i); // error: rvalue reference cannot bind to lvalue
// caref(f()); // bound to the A subobject of the B rvalue.
// carref(f()); // same as above
// caref(x); // bound to the A subobject of the result of the conversion
// cdref(2); // rcd2 refers to temporary with value 2.0
// drref(2); // rcd3 refers to temporary with value 2.0
// cdref(cvd); // error: type qualifiers dropped
// }
public void testDirectBinding_294730() throws Exception {
final String code= getAboveComment();
BindingAssertionHelper bh= new BindingAssertionHelper(code, true);
bh.assertNonProblem("dref(d)", 4);
bh.assertNonProblem("cdref(d)", 5);
bh.assertNonProblem("aref(b)", 4);
bh.assertNonProblem("caref(b)", 5);
bh.assertProblem("dref(2.0)", 4);
bh.assertProblem("dref(i)", 4);
bh.assertProblem("drref(i)", 5);
bh.assertNonProblem("caref(f())", 5);
bh.assertNonProblem("carref(f())", 6);
bh.assertNonProblem("caref(x)", 5);
bh.assertNonProblem("cdref(2)", 5);
bh.assertNonProblem("drref(2)", 5);
bh.assertProblem("cdref(cvd)", 5);
}
// struct S {
// operator int() {return 0;}
// };
// S s(){return *new S();}
// void test(int) {
// test(s());
// }
public void testSpecialRuleForImplicitObjectType_294730() throws Exception {
final String code= getAboveComment();
parseAndCheckBindings(code, ParserLanguage.CPP);
}
}

View file

@ -4296,8 +4296,51 @@ public class AST2TemplateTests extends AST2BaseTest {
// int a=1;
// a OPASSIGN(>>) 1;
// }
public void testTokenPasteShiftROperaotr_261268() throws Exception {
public void testTokenPasteShiftROperator_261268() throws Exception {
final String code= getAboveComment();
parseAndCheckBindings(code, ParserLanguage.CPP);
}
// template <class T> class X {
// void f(const T&);
// void g(T&&);
// };
// X<int&> x1; // X<int&>::f has the parameter type int&
// // X<int&>::g has the parameter type int&
// X<const int&&> x2; // X<const int&&>::f has the parameter type const int&
// // X<const int&&>::g has the parameter type const int&&
public void testRValueReferences_1_294730() throws Exception {
final String code= getAboveComment();
parseAndCheckBindings(code, ParserLanguage.CPP);
BindingAssertionHelper bh= new BindingAssertionHelper(code, true);
ICPPClassType type= bh.assertNonProblem("X<int&>", 7);
ICPPMethod[] ms= type.getMethods();
int i= ms[0].getName().equals("f") ? 0 : 1;
ICPPMethod m= ms[i];
assertEquals("int &", ASTTypeUtil.getType(m.getType().getParameterTypes()[0]));
m= ms[1-i];
assertEquals("int &", ASTTypeUtil.getType(m.getType().getParameterTypes()[0]));
type= bh.assertNonProblem("X<const int&&>", 14);
ms= type.getMethods();
i= ms[0].getName().equals("f") ? 0 : 1;
m= ms[i];
assertEquals("const int &", ASTTypeUtil.getType(m.getType().getParameterTypes()[0]));
m= ms[1-i];
assertEquals("const int &&", ASTTypeUtil.getType(m.getType().getParameterTypes()[0]));
}
// template<typename T> int f(T&&);
// void test() {
// int i;
// int j = f(i); // calls f<int&>(i)
// }
public void testRValueReferences_2_294730() throws Exception {
final String code= getAboveComment();
parseAndCheckBindings(code, ParserLanguage.CPP);
BindingAssertionHelper bh= new BindingAssertionHelper(code, true);
ICPPTemplateInstance inst= bh.assertNonProblem("f(i)", 1);
assertEquals("<int &>", ASTTypeUtil.getArgumentListString(inst.getTemplateArguments(), true));
}
}

View file

@ -9,7 +9,6 @@
* Doug Schaefer (QNX) - Initial API and implementation
* Markus Schorn (Wind River Systems)
*******************************************************************************/
package org.eclipse.cdt.core.dom;
import org.eclipse.cdt.core.model.ICProject;
@ -23,8 +22,9 @@ public interface IPDOMManager {
public static final String ID_NO_INDEXER= "org.eclipse.cdt.core.nullindexer"; //$NON-NLS-1$
public static final String ID_FAST_INDEXER= "org.eclipse.cdt.core.fastIndexer"; //$NON-NLS-1$
/**
* @deprecated, the full indexer has been removed.
* @deprecated The full indexer has been removed.
*/
@Deprecated
public static final String ID_FULL_INDEXER= "org.eclipse.cdt.core.domsourceindexer"; //$NON-NLS-1$
// Getting and setting indexer Ids

View file

@ -350,7 +350,11 @@ public class ASTTypeUtil {
result.append(getArgumentListString(inst.getTemplateArguments(), normalize));
}
} else if (type instanceof ICPPReferenceType) {
result.append(Keywords.cpAMPER);
if (((ICPPReferenceType) type).isRValueReference()) {
result.append(Keywords.cpAND);
} else {
result.append(Keywords.cpAMPER);
}
} else if (type instanceof IEnumeration) {
result.append(Keywords.ENUM);
result.append(SPACE);
@ -451,6 +455,7 @@ public class ASTTypeUtil {
// push all of the types onto the stack
int i = 0;
IQualifierType cvq= null;
ICPPReferenceType ref= null;
while (type != null && ++i < 100) {
if (!normalize) {
types = (IType[]) ArrayUtil.append(IType.class, types, type);
@ -461,18 +466,37 @@ public class ASTTypeUtil {
if (type instanceof ITypedef) {
// skip it
} else {
if (cvq != null) {
if (type instanceof IQualifierType || type instanceof IPointerType) {
type= SemanticUtil.addQualifiers(type, cvq.isConst(), cvq.isVolatile());
cvq= null;
} else {
types = (IType[]) ArrayUtil.append(IType.class, types, cvq);
if (type instanceof ICPPReferenceType) {
// reference types ignore cv-qualifiers
cvq=null;
// lvalue references win over rvalue references
if (ref == null || ref.isRValueReference()) {
// delay reference to see if there are more
ref= (ICPPReferenceType) type;
}
}
if (type instanceof IQualifierType) {
cvq= (IQualifierType) type;
} else {
types = (IType[]) ArrayUtil.append(IType.class, types, type);
if (cvq != null) {
// merge cv qualifiers
if (type instanceof IQualifierType || type instanceof IPointerType) {
type= SemanticUtil.addQualifiers(type, cvq.isConst(), cvq.isVolatile());
cvq= null;
}
}
if (type instanceof IQualifierType) {
// delay cv qualifier to merge it with others
cvq= (IQualifierType) type;
} else {
// no reference, no cv qualifier: output reference and cv-qualifier
if (ref != null) {
types = (IType[]) ArrayUtil.append(IType.class, types, ref);
ref= null;
}
if (cvq != null) {
types = (IType[]) ArrayUtil.append(IType.class, types, cvq);
cvq= null;
}
types = (IType[]) ArrayUtil.append(IType.class, types, type);
}
}
}
}

View file

@ -7,6 +7,7 @@
*
* Contributors:
* Doug Schaefer (IBM) - Initial API and implementation
* Markus Schorn (Wind River Systems)
*******************************************************************************/
package org.eclipse.cdt.core.dom.ast;
@ -24,6 +25,13 @@ public interface IASTExpression extends IASTNode {
public IType getExpressionType();
/**
* Returns whether this expression is an lvalue. LValues are for instance required on the
* left hand side of an assignment expression.
* @since 5.2
*/
public boolean isLValue();
/**
* @since 5.1
*/

View file

@ -92,14 +92,14 @@ public interface IASTLiteralExpression extends IASTExpression {
*/
public void setValue(char[] value);
/**
* @deprecated, use {@link #setValue(char[])}, instead.
*/
public void setValue(String value);
/**
* @since 5.1
*/
public IASTLiteralExpression copy();
/**
* @deprecated Replaced by {@link #setValue(char[])}.
*/
@Deprecated
public void setValue(String value);
}

View file

@ -7,6 +7,7 @@
*
* Contributors:
* Doug Schaefer (IBM) - Initial API and implementation
* Markus Schorn (Wind River Systems)
*******************************************************************************/
package org.eclipse.cdt.core.dom.ast.cpp;
@ -20,6 +21,12 @@ import org.eclipse.cdt.core.dom.ast.IASTPointerOperator;
*/
public interface ICPPASTReferenceOperator extends IASTPointerOperator {
/**
* Returns whether the operator denotes a rvalue reference (e.g. <code>int &&</code>).
* @since 5.2
*/
public boolean isRValueReference();
/**
* @since 5.1
*/

View file

@ -39,12 +39,6 @@ import org.eclipse.cdt.core.parser.IScanner;
*/
public interface ICPPNodeFactory extends INodeFactory {
/**
* @deprecated use {@link #newTranslationUnit(IScanner)}, instead.
*/
@Deprecated
public ICPPASTTranslationUnit newTranslationUnit();
/**
* Creates a new translation unit that cooperates with the given scanner in order
* to track macro-expansions and location information.
@ -152,7 +146,11 @@ public interface ICPPNodeFactory extends INodeFactory {
public IGPPASTPointer newPointerGPP();
public ICPPASTReferenceOperator newReferenceOperator();
/**
* Creates an lvalue or rvalue reference operator.
* @since 5.2
*/
public ICPPASTReferenceOperator newReferenceOperator(boolean isRValueReference);
public ICPPASTPointerToMember newPointerToMember(IASTName name);
@ -183,4 +181,14 @@ public interface ICPPNodeFactory extends INodeFactory {
*/
public ICPPASTStaticAssertDeclaration newStaticAssertion(IASTExpression condition, ICPPASTLiteralExpression message);
/**
* @deprecated Replaced by {@link #newReferenceOperator(boolean)}.
*/
@Deprecated public ICPPASTReferenceOperator newReferenceOperator();
/**
* @deprecated Replaced by {@link #newTranslationUnit(IScanner)}.
*/
@Deprecated
public ICPPASTTranslationUnit newTranslationUnit();
}

View file

@ -7,6 +7,7 @@
*
* Contributors:
* Andrew Niefer (IBM Corporation) - initial API and implementation
* Markus Schorn (Wind River Systems)
*******************************************************************************/
package org.eclipse.cdt.core.dom.ast.cpp;
@ -19,7 +20,13 @@ import org.eclipse.cdt.core.dom.ast.IType;
public interface ICPPReferenceType extends IType {
/**
* get the type that this is a reference of
* Returns the type that this is a reference of
*/
public IType getType();
/**
* Returns whether this is an rvalue reference (e.g: int&&)
* @since 5.2
*/
public boolean isRValueReference();
}

View file

@ -133,4 +133,8 @@ public abstract class ASTAmbiguousNode extends ASTNode {
afterResolution(resolver, bestAlternative);
return bestAlternative;
}
public boolean isLValue() {
return false;
}
}

View file

@ -86,4 +86,8 @@ public abstract class ASTTypeIdInitializerExpression extends ASTNode implements
}
return true;
}
public boolean isLValue() {
return false;
}
}

View file

@ -1152,6 +1152,10 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser {
public IType getExpressionType() {
throw new UnsupportedOperationException();
}
public boolean isLValue() {
throw new UnsupportedOperationException();
}
}
protected final IASTExpression castExpression(CastExprCtx ctx) throws EndOfFileException, BacktrackException {

View file

@ -120,4 +120,8 @@ public class CASTArraySubscriptExpression extends ASTNode implements
return ((IArrayType)t).getType();
return t;
}
public boolean isLValue() {
return true;
}
}

View file

@ -161,4 +161,22 @@ public class CASTBinaryExpression extends ASTNode implements
}
return t1;
}
public boolean isLValue() {
switch (getOperator()) {
case op_assign:
case op_binaryAndAssign:
case op_binaryOrAssign:
case op_binaryXorAssign:
case op_divideAssign:
case op_minusAssign:
case op_moduloAssign:
case op_multiplyAssign:
case op_plusAssign:
case op_shiftLeftAssign:
case op_shiftRightAssign:
return true;
}
return false;
}
}

View file

@ -121,4 +121,8 @@ public class CASTCastExpression extends ASTNode implements IASTCastExpression, I
IASTTypeId id= getTypeId();
return CVisitor.createType(id.getAbstractDeclarator());
}
public boolean isLValue() {
return false;
}
}

View file

@ -86,4 +86,14 @@ public class CASTCompoundStatementExpression extends ASTNode implements IGNUASTC
return null;
}
public boolean isLValue() {
IASTCompoundStatement compound = getCompoundStatement();
IASTStatement[] statements = compound.getStatements();
if (statements.length > 0) {
IASTStatement st = statements[statements.length - 1];
if (st instanceof IASTExpressionStatement)
return ((IASTExpressionStatement)st).getExpression().isLValue();
}
return false;
}
}

View file

@ -144,4 +144,8 @@ public class CASTConditionalExpression extends ASTNode implements
return t3;
return t2;
}
public boolean isLValue() {
return false;
}
}

View file

@ -102,4 +102,13 @@ public class CASTExpressionList extends ASTNode implements IASTExpressionList,
}
return null;
}
public boolean isLValue() {
for (int i = expressions.length-1; i >= 0; i--) {
IASTExpression expr= expressions[i];
if (expr != null)
return expr.isLValue();
}
return false;
}
}

View file

@ -144,6 +144,14 @@ public class CASTFieldReference extends ASTNode implements IASTFieldReference, I
return null;
}
public boolean isLValue() {
if (isPointerDereference())
return true;
return getFieldOwner().isLValue();
}
public IBinding[] findBindings(IASTName n, boolean isPrefix) {
return CVisitor.findBindingsForContentAssist(n, isPrefix);
}

View file

@ -120,4 +120,8 @@ public class CASTFunctionCallExpression extends ASTNode implements
return ((IFunctionType) type).getReturnType();
return null;
}
public boolean isLValue() {
return false;
}
}

View file

@ -111,6 +111,10 @@ public class CASTIdExpression extends ASTNode implements IASTIdExpression, IASTC
return null;
}
public boolean isLValue() {
return true;
}
public IBinding[] findBindings(IASTName n, boolean isPrefix) {
IBinding[] bindings = CVisitor.findBindingsForContentAssist(n, isPrefix);

View file

@ -100,6 +100,10 @@ public class CASTLiteralExpression extends ASTNode implements IASTLiteralExpress
return null;
}
public boolean isLValue() {
return getKind() == IASTLiteralExpression.lk_string_literal;
}
private IType classifyTypeOfFloatLiteral() {
final char[] lit= getValue();
final int len= lit.length;

View file

@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2004, 2008 IBM Corporation and others.
* Copyright (c) 2004, 2009 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
@ -60,4 +60,7 @@ public class CASTProblemExpression extends CASTProblemOwner implements IASTProbl
return null;
}
public boolean isLValue() {
return false;
}
}

View file

@ -90,4 +90,8 @@ public class CASTTypeIdExpression extends ASTNode implements IASTTypeIdExpressio
}
return CVisitor.createType(typeId.getAbstractDeclarator());
}
public boolean isLValue() {
return false;
}
}

View file

@ -122,4 +122,16 @@ public class CASTUnaryExpression extends ASTNode implements IASTUnaryExpression,
return exprType; // return the original
}
public boolean isLValue() {
switch (getOperator()) {
case op_bracketedPrimary:
return getOperand().isLValue();
case op_star:
case op_prefixDecr:
case op_prefixIncr:
return true;
default:
return false;
}
}
}

View file

@ -8,6 +8,7 @@
* Contributors:
* John Camelon (IBM) - Initial API and implementation
* Mike Kucera (IBM)
* Markus Schorn (Wind River Systems)
*******************************************************************************/
package org.eclipse.cdt.internal.core.dom.parser.cpp;
@ -25,15 +26,14 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPFunction;
import org.eclipse.cdt.internal.core.dom.parser.ASTNode;
import org.eclipse.cdt.internal.core.dom.parser.IASTAmbiguityParent;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPSemantics;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPVisitor;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil;
/**
* @author jcamelon
*/
public class CPPASTArraySubscriptExpression extends ASTNode implements ICPPASTArraySubscriptExpression, IASTAmbiguityParent {
private IASTExpression subscriptExp;
private IASTExpression arrayExpression;
private ICPPFunction overload= UNINITIALIZED_FUNCTION;
private IASTImplicitName[] implicitNames = null;
@ -104,7 +104,15 @@ public class CPPASTArraySubscriptExpression extends ASTNode implements ICPPASTAr
public ICPPFunction getOverload() {
return CPPSemantics.findOverloadedOperator(this);
if (overload == UNINITIALIZED_FUNCTION) {
overload= null;
IType t = getArrayExpression().getExpressionType();
t= SemanticUtil.getUltimateTypeUptoPointers(t);
if (t instanceof ICPPClassType && !(t instanceof ICPPUnknownType)) {
overload= CPPSemantics.findOverloadedOperator(this);
}
}
return overload;
}
@Override
@ -156,28 +164,36 @@ public class CPPASTArraySubscriptExpression extends ASTNode implements ICPPASTAr
}
public IType getExpressionType() {
ICPPFunction op = getOverload();
if (op != null) {
try {
return op.getType().getReturnType();
} catch (DOMException e) {
return e.getProblem();
}
}
IType t = getArrayExpression().getExpressionType();
t= SemanticUtil.getUltimateTypeUptoPointers(t);
try {
if (t instanceof ICPPUnknownType) {
return CPPUnknownClass.createUnnamedInstance();
}
if (t instanceof ICPPClassType) {
ICPPFunction op = getOverload();
if (op != null) {
return op.getType().getReturnType();
}
}
if (t instanceof IPointerType) {
return ((IPointerType) t).getType();
}
if (t instanceof IArrayType) {
return ((IArrayType) t).getType();
}
} catch (DOMException e) {
return e.getProblem();
if (t instanceof ICPPUnknownType) {
return CPPUnknownClass.createUnnamedInstance();
}
if (t instanceof IPointerType) {
return ((IPointerType) t).getType();
}
if (t instanceof IArrayType) {
return ((IArrayType) t).getType();
}
return null;
}
public boolean isLValue() {
ICPPFunction op = getOverload();
if (op != null) {
try {
return CPPVisitor.isLValueReference(op.getType().getReturnType());
} catch (DOMException e) {
}
}
return true;
}
}

View file

@ -172,6 +172,31 @@ public class CPPASTBinaryExpression extends ASTNode implements ICPPASTBinaryExpr
return overload = CPPSemantics.findOverloadedOperator(this);
}
public boolean isLValue() {
ICPPFunction op = getOverload();
if (op != null) {
try {
return CPPVisitor.isLValueReference(op.getType().getReturnType());
} catch (DOMException e) {
}
}
switch (getOperator()) {
case op_assign:
case op_binaryAndAssign:
case op_binaryOrAssign:
case op_binaryXorAssign:
case op_divideAssign:
case op_minusAssign:
case op_moduloAssign:
case op_multiplyAssign:
case op_plusAssign:
case op_shiftLeftAssign:
case op_shiftRightAssign:
return true;
}
return false;
}
private IType createExpressionType() {
// Check for overloaded operator.
ICPPFunction o= getOverload();

View file

@ -28,6 +28,7 @@ public class CPPASTCastExpression extends ASTNode implements ICPPASTCastExpressi
private int op;
private IASTExpression operand;
private IASTTypeId typeId;
private IType fType;
public CPPASTCastExpression() {
}
@ -117,6 +118,15 @@ public class CPPASTCastExpression extends ASTNode implements ICPPASTCastExpressi
}
public IType getExpressionType() {
return CPPVisitor.createType(typeId.getAbstractDeclarator());
if (fType == null) {
fType= CPPVisitor.createType(typeId.getAbstractDeclarator());
}
return fType;
}
public boolean isLValue() {
return CPPVisitor.isLValueReference(getExpressionType());
}
}

View file

@ -6,7 +6,8 @@
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM - Initial API and implementation
* John Camelon (IBM) - Initial API and implementation
* Markus Schorn (Wind River Systems)
*******************************************************************************/
package org.eclipse.cdt.internal.core.dom.parser.cpp;
@ -85,4 +86,15 @@ public class CPPASTCompoundStatementExpression extends ASTNode implements IGNUAS
}
return null;
}
public boolean isLValue() {
IASTCompoundStatement compound = getCompoundStatement();
IASTStatement[] statements = compound.getStatements();
if (statements.length > 0) {
IASTStatement st = statements[statements.length - 1];
if (st instanceof IASTExpressionStatement)
return ((IASTExpressionStatement)st).getExpression().isLValue();
}
return false;
}
}

View file

@ -6,7 +6,8 @@
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM - Initial API and implementation
* John Camelon (IBM) - Initial API and implementation
* Markus Schorn (Wind River Systems)
*******************************************************************************/
package org.eclipse.cdt.internal.core.dom.parser.cpp;
@ -144,4 +145,8 @@ public class CPPASTConditionalExpression extends ASTNode implements
return t3;
return t2;
}
public boolean isLValue() {
return false;
}
}

View file

@ -7,6 +7,7 @@
*
* Contributors:
* John Camelon (IBM) - Initial API and implementation
* Markus Schorn (Wind River Systems)
*******************************************************************************/
package org.eclipse.cdt.internal.core.dom.parser.cpp;
@ -151,4 +152,8 @@ public class CPPASTDeleteExpression extends ASTNode implements ICPPASTDeleteExpr
public IType getExpressionType() {
return CPPSemantics.VOID_TYPE;
}
public boolean isLValue() {
return false;
}
}

View file

@ -8,6 +8,7 @@
* Contributors:
* John Camelon (IBM) - Initial API and implementation
* Mike Kucera (IBM) - implicit names
* Markus Schorn (Wind River Systems)
*******************************************************************************/
package org.eclipse.cdt.internal.core.dom.parser.cpp;
@ -24,6 +25,7 @@ import org.eclipse.cdt.core.parser.util.ArrayUtil;
import org.eclipse.cdt.internal.core.dom.parser.ASTNode;
import org.eclipse.cdt.internal.core.dom.parser.IASTAmbiguityParent;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPSemantics;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPVisitor;
public class CPPASTExpressionList extends ASTNode implements ICPPASTExpressionList, IASTAmbiguityParent {
@ -172,22 +174,44 @@ public class CPPASTExpressionList extends ASTNode implements ICPPASTExpressionLi
}
}
public IType getExpressionType() {
ICPPFunction[] overloads = getOverloads();
if(overloads.length > 0) {
ICPPFunction last = overloads[overloads.length-1];
if(last != null) {
try {
public IType getExpressionType() {
ICPPFunction[] overloads = getOverloads();
if (overloads.length > 0) {
ICPPFunction last = overloads[overloads.length - 1];
if (last != null) {
try {
return last.getType().getReturnType();
} catch (DOMException e) { }
}
}
} catch (DOMException e) {
}
}
}
for (int i = expressions.length-1; i >= 0 ; i--) {
IASTExpression expr= expressions[i];
for (int i = expressions.length - 1; i >= 0; i--) {
IASTExpression expr = expressions[i];
if (expr != null)
return expr.getExpressionType();
}
return null;
}
return null;
}
public boolean isLValue() {
ICPPFunction[] overloads = getOverloads();
if (overloads.length > 0) {
ICPPFunction last = overloads[overloads.length - 1];
if (last != null) {
try {
return CPPVisitor.isLValueReference(last.getType().getReturnType());
} catch (DOMException e) {
return false;
}
}
}
for (int i = expressions.length-1; i >= 0; i--) {
IASTExpression expr= expressions[i];
if (expr != null)
return expr.isLValue();
}
return false;
}
}

View file

@ -9,9 +9,12 @@
* John Camelon (IBM) - Initial API and implementation
* Bryan Wilkinson (QNX)
* Mike Kucera (IBM)
* Markus Schorn (Wind River Systems)
*******************************************************************************/
package org.eclipse.cdt.internal.core.dom.parser.cpp;
import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.TDEF;
import java.util.ArrayList;
import java.util.List;
@ -31,7 +34,9 @@ import org.eclipse.cdt.core.dom.ast.IType;
import org.eclipse.cdt.core.dom.ast.IVariable;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFieldReference;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPFunction;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPMember;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPMethod;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPReferenceType;
import org.eclipse.cdt.internal.core.dom.parser.ASTNode;
import org.eclipse.cdt.internal.core.dom.parser.IASTAmbiguityParent;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPSemantics;
@ -205,6 +210,26 @@ public class CPPASTFieldReference extends ASTNode implements
return null;
}
public boolean isLValue() {
if (isPointerDereference())
return true;
IBinding b= getFieldName().resolveBinding();
try {
if (b instanceof ICPPMember && ((ICPPMember) b).isStatic())
return true;
if (b instanceof IVariable) {
if (SemanticUtil.getNestedType(((IVariable) b).getType(), TDEF) instanceof ICPPReferenceType) {
return true;
}
return getFieldOwner().isLValue();
}
} catch (DOMException e) {
}
return false;
}
public IBinding[] findBindings(IASTName n, boolean isPrefix) {
IBinding[] bindings = CPPSemantics.findBindingsForContentAssist(n, isPrefix);
List<IBinding> filtered = new ArrayList<IBinding>();

View file

@ -8,6 +8,7 @@
* Contributors:
* John Camelon (IBM) - Initial API and implementation
* Mike Kucera (IBM) - implicit names
* Markus Schorn (Wind River Systems)
*******************************************************************************/
package org.eclipse.cdt.internal.core.dom.parser.cpp;
@ -34,6 +35,7 @@ import org.eclipse.cdt.internal.core.dom.parser.ASTNode;
import org.eclipse.cdt.internal.core.dom.parser.IASTAmbiguityParent;
import org.eclipse.cdt.internal.core.dom.parser.ProblemBinding;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPSemantics;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPVisitor;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil;
@ -199,7 +201,11 @@ public class CPPASTFunctionCallExpression extends ASTNode implements
return type;
}
private IType computeExpressionType() {
public boolean isLValue() {
return CPPVisitor.isLValueReference(getExpressionType());
}
private IType computeExpressionType() {
overload= null;
try {
IType t= null;

View file

@ -6,8 +6,9 @@
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM - Initial API and implementation
* Bryan Wilkinson (QNX)
* John Camelon (IBM) - Initial API and implementation
* Bryan Wilkinson (QNX)
* Markus Schorn (Wind River Systems)
*******************************************************************************/
package org.eclipse.cdt.internal.core.dom.parser.cpp;
@ -28,9 +29,6 @@ import org.eclipse.cdt.internal.core.dom.parser.ASTNode;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPSemantics;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil;
/**
* @author jcamelon
*/
public class CPPASTIdExpression extends ASTNode implements IASTIdExpression, IASTCompletionContext {
private IASTName name;
@ -112,6 +110,14 @@ public class CPPASTIdExpression extends ASTNode implements IASTIdExpression, IAS
return null;
}
public boolean isLValue() {
IBinding b= getName().resolveBinding();
if (b instanceof IVariable || b instanceof IFunction) {
return true;
}
return false;
}
public IBinding[] findBindings(IASTName n, boolean isPrefix) {
return CPPSemantics.findBindingsForContentAssist(n, isPrefix);
}

View file

@ -12,6 +12,7 @@
package org.eclipse.cdt.internal.core.dom.parser.cpp;
import org.eclipse.cdt.core.dom.ast.ASTVisitor;
import org.eclipse.cdt.core.dom.ast.IASTLiteralExpression;
import org.eclipse.cdt.core.dom.ast.IBasicType;
import org.eclipse.cdt.core.dom.ast.IScope;
import org.eclipse.cdt.core.dom.ast.IType;
@ -113,6 +114,10 @@ public class CPPASTLiteralExpression extends ASTNode implements ICPPASTLiteralEx
return null;
}
public boolean isLValue() {
return getKind() == IASTLiteralExpression.lk_string_literal;
}
private IValue getStringLiteralSize() {
char[] value= getValue();
int length= value.length-1;

View file

@ -256,4 +256,8 @@ public class CPPASTNewExpression extends ASTNode implements
}
return new CPPPointerType(t);
}
public boolean isLValue() {
return false;
}
}

View file

@ -1,12 +1,12 @@
/*******************************************************************************
* Copyright (c) 2004, 2008 IBM Corporation and others.
* Copyright (c) 2004, 2009 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
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM - Initial API and implementation
* John Camelon (IBM) - Initial API and implementation
* Markus Schorn (Wind River Systems)
*******************************************************************************/
package org.eclipse.cdt.internal.core.dom.parser.cpp;
@ -16,9 +16,6 @@ import org.eclipse.cdt.core.dom.ast.IASTProblem;
import org.eclipse.cdt.core.dom.ast.IASTProblemExpression;
import org.eclipse.cdt.core.dom.ast.IType;
/**
* @author jcamelon
*/
public class CPPASTProblemExpression extends CPPASTProblemOwner implements IASTProblemExpression {
public CPPASTProblemExpression() {
@ -58,4 +55,8 @@ public class CPPASTProblemExpression extends CPPASTProblemOwner implements IASTP
public IType getExpressionType() {
return null;
}
public boolean isLValue() {
return false;
}
}

View file

@ -20,11 +20,18 @@ import org.eclipse.cdt.internal.core.dom.parser.ASTNode;
*/
public class CPPASTReferenceOperator extends ASTNode implements ICPPASTReferenceOperator {
public CPPASTReferenceOperator() {
private final boolean fIsRValue;
public CPPASTReferenceOperator(boolean isRValueReference) {
fIsRValue= isRValueReference;
}
public boolean isRValueReference() {
return fIsRValue;
}
public CPPASTReferenceOperator copy() {
CPPASTReferenceOperator copy = new CPPASTReferenceOperator();
CPPASTReferenceOperator copy = new CPPASTReferenceOperator(fIsRValue);
copy.setOffsetAndLength(this);
return copy;
}

View file

@ -19,9 +19,6 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTSimpleTypeConstructorExpression;
import org.eclipse.cdt.internal.core.dom.parser.ASTNode;
import org.eclipse.cdt.internal.core.dom.parser.IASTAmbiguityParent;
/**
* @author jcamelon
*/
public class CPPASTSimpleTypeConstructorExpression extends ASTNode implements
ICPPASTSimpleTypeConstructorExpression, IASTAmbiguityParent {
@ -100,4 +97,8 @@ public class CPPASTSimpleTypeConstructorExpression extends ASTNode implements
public IType getExpressionType() {
return new CPPBasicType(CPPBasicType.getKind(st), 0);
}
public boolean isLValue() {
return false;
}
}

View file

@ -6,21 +6,18 @@
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM - Initial API and implementation
* John Camelon (IBM) - Initial API and implementation
* Markus Schorn (Wind River Systems)
*******************************************************************************/
package org.eclipse.cdt.internal.core.dom.parser.cpp;
import org.eclipse.cdt.core.dom.ast.ASTVisitor;
import org.eclipse.cdt.core.dom.ast.IASTTypeId;
import org.eclipse.cdt.core.dom.ast.IASTTypeIdExpression;
import org.eclipse.cdt.core.dom.ast.IType;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTypeIdExpression;
import org.eclipse.cdt.internal.core.dom.parser.ASTNode;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPVisitor;
/**
* @author jcamelon
*/
public class CPPASTTypeIdExpression extends ASTNode implements ICPPASTTypeIdExpression {
private int op;
@ -86,11 +83,21 @@ public class CPPASTTypeIdExpression extends ASTNode implements ICPPASTTypeIdExpr
public IType getExpressionType() {
switch (getOperator()) {
case IASTTypeIdExpression.op_sizeof:
case op_sizeof:
return CPPVisitor.get_SIZE_T(this);
case IASTTypeIdExpression.op_typeid:
case op_typeid:
return CPPVisitor.get_type_info(this);
}
return CPPVisitor.createType(getTypeId());
}
public boolean isLValue() {
switch(getOperator()) {
case op_typeid:
return true;
}
return false;
}
}

View file

@ -6,7 +6,8 @@
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM - Initial API and implementation
* John Camelon (IBM) - Initial API and implementation
* Markus Schorn (Wind River Systems)
*******************************************************************************/
package org.eclipse.cdt.internal.core.dom.parser.cpp;
@ -20,9 +21,6 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTypenameExpression;
import org.eclipse.cdt.internal.core.dom.parser.ASTNode;
import org.eclipse.cdt.internal.core.dom.parser.IASTAmbiguityParent;
/**
* @author jcamelon
*/
public class CPPASTTypenameExpression extends ASTNode implements
ICPPASTTypenameExpression, IASTAmbiguityParent {
@ -135,4 +133,8 @@ public class CPPASTTypenameExpression extends ASTNode implements
}
return null;
}
public boolean isLValue() {
return false;
}
}

View file

@ -271,6 +271,26 @@ public class CPPASTUnaryExpression extends ASTNode implements ICPPASTUnaryExpres
return origType;
}
public boolean isLValue() {
ICPPFunction op = getOverload();
if (op != null) {
try {
return CPPVisitor.isLValueReference(op.getType().getReturnType());
} catch (DOMException e) {
}
}
switch (getOperator()) {
case op_bracketedPrimary:
return getOperand().isLValue();
case op_star:
case op_prefixDecr:
case op_prefixIncr:
return true;
default:
return false;
}
}
private IType findOperatorReturnType() {
ICPPFunction operatorFunction = getOverload();

View file

@ -100,7 +100,7 @@ public class CPPClassScope extends CPPScope implements ICPPClassScope {
char[] className = name.getLookupKey();
IParameter[] voidPs = new IParameter[] { new CPPParameter(CPPSemantics.VOID_TYPE, 0) };
IType pType = new CPPReferenceType(SemanticUtil.addQualifiers(clsType, true, false));
IType pType = new CPPReferenceType(SemanticUtil.addQualifiers(clsType, true, false), false);
IParameter[] ps = new IParameter[] { new CPPParameter(pType, 0) };
int i= 0;
@ -124,7 +124,7 @@ public class CPPClassScope extends CPPScope implements ICPPClassScope {
if (!ia.hasUserDeclaredCopyAssignmentOperator()) {
//copy assignment operator: A& operator = (const A &)
IType refType = new CPPReferenceType(clsType);
IType refType = new CPPReferenceType(clsType, false);
ICPPFunctionType ft= CPPVisitor.createImplicitFunctionType(refType, ps, false, false);
ICPPMethod m = new CPPImplicitMethod(this, OverloadableOperator.ASSIGN.toCharArray(), ft, ps);
implicits[i++] = m;

View file

@ -454,7 +454,11 @@ public class CPPNodeFactory extends NodeFactory implements ICPPNodeFactory {
}
public ICPPASTReferenceOperator newReferenceOperator() {
return new CPPASTReferenceOperator();
return new CPPASTReferenceOperator(false);
}
public ICPPASTReferenceOperator newReferenceOperator(boolean isRValueReference) {
return new CPPASTReferenceOperator(isRValueReference);
}
public ICPPASTPointerToMember newPointerToMember(IASTName name) {

View file

@ -7,6 +7,7 @@
*
* Contributors:
* Andrew Niefer (IBM Corporation) - initial API and implementation
* Markus Schorn (Wind River Systems)
*******************************************************************************/
package org.eclipse.cdt.internal.core.dom.parser.cpp;
@ -20,18 +21,29 @@ import org.eclipse.cdt.internal.core.dom.parser.ITypeMarshalBuffer;
import org.eclipse.core.runtime.CoreException;
public class CPPReferenceType implements ICPPReferenceType, ITypeContainer, ISerializableType {
IType type = null;
private IType fType = null;
private boolean fIsRValue;
public CPPReferenceType(IType type) {
this.type = type;
public CPPReferenceType(IType type, boolean isRValue) {
fIsRValue= isRValue;
setType(type);
}
public IType getType() {
return type;
return fType;
}
public boolean isRValueReference() {
return fIsRValue;
}
public void setType(IType t) {
type = t;
if (t instanceof ICPPReferenceType) {
final ICPPReferenceType rt = (ICPPReferenceType) t;
fIsRValue = fIsRValue && rt.isRValueReference();
t= rt.getType();
}
fType= t;
}
public boolean isSameType(IType obj) {
@ -40,11 +52,36 @@ public class CPPReferenceType implements ICPPReferenceType, ITypeContainer, ISer
if (obj instanceof ITypedef)
return ((ITypedef)obj).isSameType(this);
if (type == null)
return false;
if (obj instanceof ICPPReferenceType) {
return type.isSameType(((ICPPReferenceType) obj).getType());
final ICPPReferenceType rhs = (ICPPReferenceType) obj;
IType t1= getType();
IType t2= rhs.getType();
boolean rv1= isRValueReference();
boolean rv2= rhs.isRValueReference();
for(;;) {
if (t1 instanceof ITypedef) {
t1= ((ITypedef) t1).getType();
} else if (t1 instanceof ICPPReferenceType) {
rv1= rv1 && ((ICPPReferenceType) t1).isRValueReference();
t1= ((ICPPReferenceType) t1).getType();
} else {
break;
}
}
for(;;) {
if (t2 instanceof ITypedef) {
t2= ((ITypedef) t2).getType();
} else if (t2 instanceof ICPPReferenceType) {
rv2= rv2 && ((ICPPReferenceType) t2).isRValueReference();
t2= ((ICPPReferenceType) t2).getType();
} else {
break;
}
}
if (t1 == null)
return false;
return rv1 == rv2 && t1.isSameType(t2);
}
return false;
}
@ -67,12 +104,15 @@ public class CPPReferenceType implements ICPPReferenceType, ITypeContainer, ISer
public void marshal(ITypeMarshalBuffer buffer) throws CoreException {
int firstByte= ITypeMarshalBuffer.REFERENCE;
if (isRValueReference()) {
firstByte |= ITypeMarshalBuffer.FLAG1;
}
buffer.putByte((byte) firstByte);
buffer.marshalType(getType());
}
public static IType unmarshal(int firstByte, ITypeMarshalBuffer buffer) throws CoreException {
IType nested= buffer.unmarshalType();
return new CPPReferenceType(nested);
return new CPPReferenceType(nested, (firstByte & ITypeMarshalBuffer.FLAG1) != 0);
}
}

View file

@ -2947,17 +2947,16 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
// __attribute__ in-between pointers
__attribute_decl_seq(supportAttributeSpecifiers, false);
if (LT(1) == IToken.tAMPER) {
// boolean isRestrict= false;
IToken lastToken= consume();
final int from= lastToken.getOffset();
final int lt1 = LT(1);
if (lt1 == IToken.tAMPER || lt1 == IToken.tAND) {
IToken endToken= consume();
final int offset= endToken.getOffset();
if (allowCPPRestrict && LT(1) == IToken.t_restrict) {
// isRestrict= true;
lastToken= consume();
endToken= consume();
}
ICPPASTReferenceOperator refOp = nodeFactory.newReferenceOperator();
((ASTNode) refOp).setOffsetAndLength(from, lastToken.getEndOffset()-from);
collection.add(refOp);
ICPPASTReferenceOperator refOp = nodeFactory.newReferenceOperator(lt1 == IToken.tAND);
collection.add(setRange(refOp, offset, endToken.getEndOffset()));
return;
}

View file

@ -18,6 +18,7 @@ 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.Collection;
import java.util.HashMap;
import java.util.HashSet;
@ -1799,7 +1800,7 @@ public class CPPSemantics {
return !b1FromIndex ? 1 : -1;
} else if (b1FromIndex) {
// Both are from index.
if (data.tu != null) {
if (data != null && data.tu != null) {
boolean b1Reachable= isReachableFromAst(data.tu, b1);
boolean b2Reachable= isReachableFromAst(data.tu, b2);
if (b1Reachable != b2Reachable) {
@ -2047,7 +2048,7 @@ public class CPPSemantics {
}
if (!data.forFunctionDeclaration() || data.forExplicitFunctionSpecialization()) {
CPPTemplates.instantiateFunctionTemplates(fns, data.getFunctionArgumentTypes(), data.astName);
CPPTemplates.instantiateFunctionTemplates(fns, data.getFunctionArgumentTypes(), data.getFunctionArgumentLValues(), data.astName);
}
// Reduce our set of candidate functions to only those who have the right number of parameters
@ -2069,7 +2070,6 @@ public class CPPSemantics {
return firstViable;
// The arguments the function is being called with
final IASTExpression[] args= data.getFunctionArguments();
IType[] argTypes = data.getFunctionArgumentTypes();
if (CPPTemplates.containsDependentType(argTypes)) {
if (viableCount == 1)
@ -2086,7 +2086,7 @@ public class CPPSemantics {
if (fn == null)
continue;
final FunctionCost fnCost= costForFunctionCall(fn, argTypes, args, allowUDC, data);
final FunctionCost fnCost= costForFunctionCall(fn, allowUDC, data);
if (fnCost == null)
continue;
@ -2137,8 +2137,10 @@ public class CPPSemantics {
return bestFnCost.getFunction();
}
private static FunctionCost costForFunctionCall(IFunction fn, IType[] argTypes, IASTExpression[] args,
boolean allowUDC, LookupData data) throws DOMException {
private static FunctionCost costForFunctionCall(IFunction fn, boolean allowUDC, LookupData data)
throws DOMException {
IType[] argTypes = data.getFunctionArgumentTypes();
BitSet isLValue= data.getFunctionArgumentLValues();
final ICPPFunctionType ftype= (ICPPFunctionType) fn.getType();
if (ftype == null)
return null;
@ -2149,9 +2151,7 @@ public class CPPSemantics {
implicitType = getImplicitType((ICPPMethod) fn, ftype.isConst(), ftype.isVolatile());
if (data.firstArgIsImpliedMethodArg) {
argTypes = ArrayUtil.removeFirst(argTypes);
if (args != null) {
args = ArrayUtil.removeFirst(args);
}
isLValue = isLValue.get(1, isLValue.size());
}
}
@ -2175,7 +2175,7 @@ public class CPPSemantics {
} else if (thisType.isSameType(implicitType)) {
cost = new Cost(thisType, implicitType, Rank.IDENTITY);
} else {
cost = Conversions.checkImplicitConversionSequence(sourceIsLValue, thisType, implicitType, UDCMode.noUDC, true);
cost = Conversions.checkImplicitConversionSequence(implicitType, thisType, sourceIsLValue, UDCMode.noUDC, true);
if (cost.getRank() == Rank.NO_MATCH) {
if (CPPTemplates.isDependentType(implicitType) || CPPTemplates.isDependentType(thisType)) {
IType s= getNestedType(thisType, TDEF|REF|CVTYPE);
@ -2195,12 +2195,11 @@ public class CPPSemantics {
final UDCMode udc = allowUDC ? UDCMode.deferUDC : UDCMode.noUDC;
for (int j = 0; j < sourceLen; j++) {
final IType argType= argTypes[j];
final IType argType= SemanticUtil.getNestedType(argTypes[j], TDEF | REF);
if (argType == null)
return null;
final IASTExpression arg= args != null && j < args.length ? args[j] : null;
final boolean sourceIsLValue = arg != null && !CPPVisitor.isRValue(arg);
final boolean sourceIsLValue = isLValue.get(j);
IType paramType;
if (j < paramTypes.length) {
@ -2218,7 +2217,7 @@ public class CPPSemantics {
} else {
if (CPPTemplates.isDependentType(paramType))
return CONTAINS_DEPENDENT_TYPES;
cost = Conversions.checkImplicitConversionSequence(sourceIsLValue, argType, paramType, udc, false);
cost = Conversions.checkImplicitConversionSequence(paramType, argType, sourceIsLValue, udc, false);
}
if (cost.getRank() == Rank.NO_MATCH)
return null;
@ -2236,7 +2235,7 @@ public class CPPSemantics {
owner= CPPTemplates.instantiateWithinClassTemplate((ICPPClassTemplate) owner);
}
implicitType= SemanticUtil.addQualifiers(owner, isConst, isVolatile);
implicitType= new CPPReferenceType(implicitType);
implicitType= new CPPReferenceType(implicitType, false);
return implicitType;
}

View file

@ -13,11 +13,10 @@
*******************************************************************************/
package org.eclipse.cdt.internal.core.dom.parser.cpp.semantics;
import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.ALLCVQ;
import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.CVTYPE;
import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.TDEF;
import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.*;
import java.util.ArrayList;
import java.util.BitSet;
import java.util.Collections;
import java.util.List;
@ -122,6 +121,7 @@ import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPMethodSpecialization;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPMethodTemplateSpecialization;
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.CPPReferenceType;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPTemplateArgument;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPTemplateDefinition;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPTemplateNonTypeParameter;
@ -634,7 +634,7 @@ public class CPPTemplates {
* 14.8.2.1
*/
static private ICPPTemplateArgument[] deduceTemplateFunctionArguments(ICPPFunctionTemplate template,
ICPPTemplateArgument[] tmplArgs, IType[] fnArgs, CPPTemplateParameterMap map) throws DOMException {
ICPPTemplateArgument[] tmplArgs, IType[] fnArgs, BitSet argIsLValue, CPPTemplateParameterMap map) throws DOMException {
final ICPPTemplateParameter[] tmplParams = template.getTemplateParameters();
final int length = tmplParams.length;
if (tmplArgs.length > length)
@ -654,7 +654,7 @@ public class CPPTemplates {
result[i]= tmplArg;
}
if (!deduceTemplateParameterMapFromFunctionParameters(template, fnArgs, map, false))
if (!deduceTemplateParameterMapFromFunctionParameters(template, fnArgs, argIsLValue, map, false))
return null;
for (int i = 0; i < length; i++) {
@ -1360,7 +1360,7 @@ public class CPPTemplates {
return result;
}
static protected void instantiateFunctionTemplates(IFunction[] functions, IType[] fnArgs, IASTName name) {
static protected void instantiateFunctionTemplates(IFunction[] functions, IType[] fnArgs, BitSet argIsLValue, IASTName name) {
boolean requireTemplate= false;
if (name != null) {
if (name.getPropertyInParent() == ICPPASTTemplateId.TEMPLATE_NAME) {
@ -1399,7 +1399,7 @@ public class CPPTemplates {
}
CPPTemplateParameterMap map= new CPPTemplateParameterMap(fnArgs.length);
try {
ICPPTemplateArgument[] args= deduceTemplateFunctionArguments(template, templateArguments, fnArgs, map);
ICPPTemplateArgument[] args= deduceTemplateFunctionArguments(template, templateArguments, fnArgs, argIsLValue, map);
if (args != null) {
IBinding instance= instantiateFunctionTemplate(template, args);
if (instance instanceof IFunction) {
@ -1458,7 +1458,7 @@ public class CPPTemplates {
* returns <code>false</code> if there is no mapping.
*/
private static boolean deduceTemplateParameterMapFromFunctionParameters(ICPPFunctionTemplate template,
IType[] fnArgs, CPPTemplateParameterMap map, boolean checkExactMatch) throws DOMException {
IType[] fnArgs, BitSet argIsLValue, CPPTemplateParameterMap map, boolean checkExactMatch) throws DOMException {
try {
IType[] fnPars = template.getType().getParameterTypes();
if (fnPars.length == 0)
@ -1478,12 +1478,24 @@ public class CPPTemplates {
IType par= instPars[j];
boolean isDependentPar= isDependentType(par);
if (checkExactMatch || isDependentPar) {
boolean isReferenceTypeParameter= false;
IType arg = fnArgs[j];
par= SemanticUtil.getNestedType(par, SemanticUtil.TDEF); // adjustParameterType preserves typedefs
// 14.8.2.1-2
final boolean isReferenceTypeParameter = par instanceof ICPPReferenceType;
IType arg= getArgumentTypeForDeduction(fnArgs[j], isReferenceTypeParameter);
if (isReferenceTypeParameter)
if (par instanceof ICPPReferenceType) {
// If P is an rvalue reference to a cv-unqualified template parameter and the argument is an
// lvalue, the type A& 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)) {
arg= new CPPReferenceType(getSimplifiedType(arg), false);
} else {
arg= getArgumentTypeForDeduction(arg, true);
}
par= SemanticUtil.getNestedType(par, SemanticUtil.REF | SemanticUtil.TDEF);
} else {
arg= getArgumentTypeForDeduction(arg, false);
}
if (!checkExactMatch) {
// 14.8.2.1-3
@ -1841,7 +1853,7 @@ public class CPPTemplates {
CPPTemplateParameterMap map= new CPPTemplateParameterMap(2);
final IType[] transferredParameterTypes = ((ICPPFunction) transferredTemplate).getType().getParameterTypes();
if (!deduceTemplateParameterMapFromFunctionParameters(f2, transferredParameterTypes, map, true))
if (!deduceTemplateParameterMapFromFunctionParameters(f2, transferredParameterTypes, new BitSet(), map, true))
return false;
final ICPPTemplateParameter[] tmplParams = f2.getTemplateParameters();
@ -2078,7 +2090,7 @@ public class CPPTemplates {
} else if (paramType instanceof IArrayType) {
paramType = new CPPPointerType(((IArrayType) paramType).getType());
}
Cost cost = Conversions.checkImplicitConversionSequence(true, arg, paramType, UDCMode.noUDC, false);
Cost cost = Conversions.checkImplicitConversionSequence(paramType, arg, true, UDCMode.noUDC, false);
return cost != null && cost.getRank() != Rank.NO_MATCH;
}

View file

@ -46,7 +46,7 @@ public final class CPPVariableReadWriteFlags extends VariableReadWriteFlags {
@Override
protected int rwAssignmentToType(IType type, int indirection) {
if (indirection == 0) {
if (!(type instanceof ICPPReferenceType)) {
if (!(type instanceof ICPPReferenceType) || ((ICPPReferenceType) type).isRValueReference()) {
return READ;
}
type= ((ICPPReferenceType) type).getType();

View file

@ -44,7 +44,6 @@ import org.eclipse.cdt.core.dom.ast.IASTInitializer;
import org.eclipse.cdt.core.dom.ast.IASTInitializerExpression;
import org.eclipse.cdt.core.dom.ast.IASTInitializerList;
import org.eclipse.cdt.core.dom.ast.IASTLabelStatement;
import org.eclipse.cdt.core.dom.ast.IASTLiteralExpression;
import org.eclipse.cdt.core.dom.ast.IASTName;
import org.eclipse.cdt.core.dom.ast.IASTNamedTypeSpecifier;
import org.eclipse.cdt.core.dom.ast.IASTNode;
@ -1617,7 +1616,8 @@ public class CPPVisitor extends ASTQueries {
} else if (ptrOp instanceof IASTPointer) {
type = new CPPPointerType(type, (IASTPointer) ptrOp);
} else if (ptrOp instanceof ICPPASTReferenceOperator) {
type = new CPPReferenceType(type);
final ICPPASTReferenceOperator refOp = (ICPPASTReferenceOperator) ptrOp;
type = new CPPReferenceType(type, refOp.isRValueReference());
}
}
return type;
@ -1976,37 +1976,9 @@ public class CPPVisitor extends ASTQueries {
return false;
}
/**
* [3.10] Lvalues and Rvalues
* @param exp
* @return whether the specified expression is an rvalue
*/
static boolean isRValue(IASTExpression exp) {
if (exp instanceof IASTUnaryExpression) {
IASTUnaryExpression ue= (IASTUnaryExpression) exp;
if (ue.getOperator() == IASTUnaryExpression.op_amper) {
return true;
}
}
if (exp instanceof IASTLiteralExpression)
return true;
if (exp instanceof IASTFunctionCallExpression) {
try {
IASTFunctionCallExpression fc= (IASTFunctionCallExpression) exp;
IASTExpression fne= fc.getFunctionNameExpression();
if (fne instanceof IASTIdExpression) {
IASTIdExpression ide= (IASTIdExpression) fne;
IBinding b= ide.getName().resolveBinding();
if (b instanceof IFunction) {
IFunctionType tp= ((IFunction) b).getType();
return !(tp.getReturnType() instanceof ICPPReferenceType);
}
}
} catch (DOMException de) {
// fall-through
}
}
return false;
public static boolean isLValueReference(IType t) {
t= SemanticUtil.getNestedType(t, TDEF);
return t instanceof ICPPReferenceType && !((ICPPReferenceType) t).isRValueReference();
}
/**

View file

@ -17,7 +17,8 @@ package org.eclipse.cdt.internal.core.dom.parser.cpp.semantics;
import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CVQualifier._;
import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.*;
import org.eclipse.cdt.core.CCorePlugin;
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.IASTLiteralExpression;
@ -43,7 +44,6 @@ 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.ICPPSpecialization;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateInstance;
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;
@ -51,8 +51,7 @@ 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.ICPPDeferredClassInstance;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.Cost.Rank;
import org.eclipse.cdt.internal.core.index.IIndexFragmentBinding;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.Cost.ReferenceBinding;
/**
* Routines for calculating the cost of conversions.
@ -60,117 +59,158 @@ import org.eclipse.core.runtime.CoreException;
public class Conversions {
enum UDCMode {allowUDC, noUDC, deferUDC}
private static final BitSet RVBITSET = new BitSet();
private static final BitSet LVBITSET = new BitSet();
static {
LVBITSET.set(0, true);
}
/**
* Computes the cost of an implicit conversion sequence
* [over.best.ics] 13.3.3.1
* @param sourceIsLValue whether the source type is an lvalue
* @param source the source (argument) type
* @param target the target (parameter) type
* @param isImpliedObject
*
* @param exprType the source (argument) type
* @param exprIsLValue whether the source type is an lvalue
* @param isImpliedObjectType
* @return the cost of converting from source to target
* @throws DOMException
*/
public static Cost checkImplicitConversionSequence(boolean sourceIsLValue, IType source,
IType target, UDCMode udc, boolean isImpliedObject) throws DOMException {
if (isImpliedObject) {
public static Cost checkImplicitConversionSequence(IType target, IType exprType,
boolean exprIsLValue, UDCMode udc, boolean isImpliedObjectType) throws DOMException {
if (isImpliedObjectType) {
udc= UDCMode.noUDC;
}
target= getNestedType(target, TDEF);
source= getNestedType(source, TDEF);
exprType= getNestedType(exprType, TDEF | REF);
if (target instanceof ICPPReferenceType) {
// [8.5.3-5] initialization of a reference
IType cv1T1= getNestedType(target, TDEF | REF);
final boolean isLValueRef= !((ICPPReferenceType) target).isRValueReference();
final IType cv1T1= getNestedType(target, TDEF | REF);
final IType T1= getNestedType(cv1T1, TDEF | REF | ALLCVQ);
final IType cv2T2= exprType;
final IType T2= getNestedType(cv2T2, TDEF | REF | ALLCVQ);
if (source instanceof ICPPReferenceType) {
sourceIsLValue= true;
source= getNestedType(source, TDEF | REF);
final boolean isImplicitWithoutRefQualifier = isImpliedObjectType; // mstodo need to pass this information to here
ReferenceBinding refBindingType= ReferenceBinding.OTHER;
if (!isImplicitWithoutRefQualifier) {
if (isLValueRef) {
refBindingType= ReferenceBinding.LVALUE_REF;
} else if (exprIsLValue) {
refBindingType= ReferenceBinding.RVALUE_REF_BINDS_RVALUE;
}
}
IType T2= getNestedType(source, TDEF | REF | ALLCVQ);
// [8.5.3-5] Is an lvalue (but is not a bit-field), and "cv1 T1" is reference-compatible with "cv2 T2,"
if (sourceIsLValue) {
Cost cost= isReferenceCompatible(cv1T1, source, isImpliedObject);
if (cost != null) {
// [8.5.3-5] this is a direct reference binding
// [13.3.3.1.4-1] direct binding has either identity or conversion rank.
if (cost.getInheritanceDistance() > 0) {
cost.setRank(Rank.CONVERSION);
// If the reference is an lvalue reference and ...
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) {
// ... and "cv1 T1" is reference-compatible with "cv2 T2"
Cost cost= isReferenceCompatible(cv1T1, cv2T2, isImpliedObjectType);
if (cost != null) {
// [13.3.3.1.4-1] direct binding has either identity or conversion rank.
if (cost.getInheritanceDistance() > 0) {
cost.setRank(Rank.CONVERSION);
}
cost.setReferenceBinding(refBindingType);
return cost;
}
}
// ... or has a class type (i.e., T2 is a class type), where T1 is not reference-related to T2, and can be
// 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 (cost != null) {
cost.setReferenceBinding(refBindingType);
return cost;
}
}
}
// 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.
boolean ok;
if (isLValueRef) {
// mstodo
// Special rule for implicit object type, 13.3.1-5:
// Even if the implicit object type is not const-qualified, an rvalue temporary can
// be bound to the parameter as long as in all other respects ....
//
final CVQualifier cvq = getCVQualifier(cv1T1);
ok = cvq == CVQualifier.c;
} else {
ok= !exprIsLValue;
}
if (!ok) {
return new Cost(exprType, cv1T1, Rank.NO_MATCH);
}
// 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 (cost != null) {
// [13.3.3.1.4-1] direct binding has either identity or conversion rank.
if (cost.getInheritanceDistance() > 0) {
cost.setRank(Rank.CONVERSION);
}
cost.setReferenceBinding(refBindingType);
return cost;
}
}
// 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
// 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);
if (cost != null) {
cost.setReferenceBinding(refBindingType);
return cost;
}
}
}
// 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 (cost != null) {
cost.setReferenceBinding(refBindingType);
return cost;
}
}
if (T2 instanceof ICPPClassType && udc != UDCMode.noUDC) {
// Or has a class type (i.e., T2 is a class type) and can be implicitly converted to
// an lvalue of type "cv3 T3," where "cv1 T1" is reference-compatible with "cv3 T3" 92)
// (this conversion is selected by enumerating the applicable conversion functions
// (13.3.1.6) and choosing the best one through overload resolution (13.3)).
ICPPMethod[] fcns= SemanticUtil.getConversionOperators((ICPPClassType) T2);
Cost operatorCost= null;
boolean ambiguousConversionOperator= false;
if (fcns.length > 0 && !(fcns[0] instanceof IProblemBinding)) {
for (final ICPPMethod op : fcns) {
IType newSource= op.getType().getReturnType();
if (newSource instanceof ICPPReferenceType) { // require an lvalue
IType cvT2= getNestedType(newSource, TDEF | REF);
Cost cost2= isReferenceCompatible(cv1T1, cvT2, false);
if (cost2 != null) {
int cmp= cost2.compareTo(operatorCost);
if (cmp <= 0) {
ambiguousConversionOperator= cmp == 0;
operatorCost= cost2;
operatorCost.setUserDefinedConversion(op);
}
}
}
}
}
// Otherwise, a temporary of type cv1 T1 is created and initialized from the initializer
// expression using the rules for a non-reference copy initialization (8.5). The reference is then
// bound to the temporary. If T1 is reference-related to T2, cv1 must be the same cv-qualification
// as, or greater cv-qualification than, cv2; otherwise, the program is ill-formed.
if (operatorCost != null && !ambiguousConversionOperator) {
if (isImpliedObject) {
operatorCost.setInheritanceDistance(0);
// 13.3.3.1.7 no temporary object when converting the implicit object parameter
if (!isImpliedObjectType) {
if (isReferenceRelated(T1, T2) < 0 || compareQualifications(cv1T1, cv2T2) >= 0) {
Cost cost= nonReferenceConversion(exprIsLValue, cv2T2, T1, udc, false);
if (!isImplicitWithoutRefQualifier) {
cost.setReferenceBinding(isLValueRef ? ReferenceBinding.LVALUE_REF : ReferenceBinding.RVALUE_REF_BINDS_RVALUE);
}
return operatorCost;
return cost;
}
}
// [8.5.3-5] Direct binding failed - Otherwise
boolean cv1isConst= getCVQualifier(cv1T1) == CVQualifier.c;
if (cv1isConst) {
if (!sourceIsLValue && T2 instanceof ICPPClassType) {
Cost cost= isReferenceCompatible(cv1T1, source, isImpliedObject);
if (cost != null)
return cost;
}
// 5 - Otherwise
// Otherwise, a temporary of type "cv1 T1" is created and initialized from
// the initializer expression using the rules for a non-reference copy
// initialization (8.5). The reference is then bound to the temporary.
// If T1 is reference-related to T2, cv1 must be the same cv-qualification 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 (!isImpliedObject) {
IType T1= getNestedType(cv1T1, TDEF | REF | ALLCVQ);
boolean illformed= isReferenceRelated(T1, T2) >= 0 && compareQualifications(cv1T1, source) < 0;
// We must do a non-reference initialization
if (!illformed) {
return nonReferenceConversion(sourceIsLValue, source, T1, udc, isImpliedObject);
}
}
}
return new Cost(source, cv1T1, Rank.NO_MATCH);
return new Cost(exprType, cv1T1, Rank.NO_MATCH);
}
// Non-reference binding
IType uqsource= getNestedType(source, TDEF | REF | ALLCVQ);
IType uqsource= getNestedType(exprType, TDEF | REF | ALLCVQ);
IType uqtarget= getNestedType(target, TDEF | REF | ALLCVQ);
// [13.3.3.1-6] Derived to base conversion
@ -186,13 +226,53 @@ public class Conversions {
}
}
return nonReferenceConversion(sourceIsLValue, source, uqtarget, udc, isImpliedObject);
return nonReferenceConversion(exprIsLValue, exprType, uqtarget, udc, isImpliedObjectType);
}
/**
* 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)
throws DOMException {
ICPPMethod[] fcns= SemanticUtil.getConversionOperators((ICPPClassType) T2);
Cost operatorCost= null;
FunctionCost bestUdcCost= null;
boolean ambiguousConversionOperator= false;
if (fcns.length > 0 && !(fcns[0] instanceof IProblemBinding)) {
for (final ICPPMethod op : fcns) {
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.getImplicitType(op, ft.isConst(), ft.isVolatile());
Cost udcCost= isReferenceCompatible(getNestedType(implicitObjectType, 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
if (cost != null) {
bestUdcCost= udcFuncCost;
ambiguousConversionOperator= cmp == 0;
operatorCost= cost;
operatorCost.setUserDefinedConversion(op);
}
}
}
}
}
}
if (operatorCost != null && !ambiguousConversionOperator) {
return operatorCost;
}
return null;
}
private static Cost nonReferenceConversion(boolean sourceIsLValue, IType source, IType target, UDCMode udc, boolean isImpliedObject) throws DOMException {
// [13.3.3.1-6] Subsume cv-qualifications
IType uqSource= SemanticUtil.getNestedType(source, TDEF | ALLCVQ);
Cost cost= checkStandardConversionSequence(uqSource, target, isImpliedObject);
Cost cost= checkStandardConversionSequence(uqSource, sourceIsLValue, target, isImpliedObject);
if (cost.getRank() != Rank.NO_MATCH || udc == UDCMode.noUDC)
return cost;
@ -327,10 +407,10 @@ public class Conversions {
* base conversion does not cause any costs.
* @throws DOMException
*/
private static final Cost checkStandardConversionSequence(IType source, IType target,
private static final Cost checkStandardConversionSequence(IType source, boolean isLValue, IType target,
boolean isImplicitThis) throws DOMException {
final Cost cost= new Cost(source, target, Rank.IDENTITY);
if (lvalue_to_rvalue(cost))
if (lvalue_to_rvalue(cost, isLValue))
return cost;
if (promotion(cost))
@ -370,25 +450,25 @@ public class Conversions {
// 13.3.1.4 Copy initialization of class by user-defined conversion
if (t instanceof ICPPClassType) {
Cost cost1= null;
FunctionCost cost1= null;
Cost cost2= null;
ICPPConstructor[] ctors= ((ICPPClassType) t).getConstructors();
CPPTemplates.instantiateFunctionTemplates(ctors, new IType[]{source}, null);
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();
Cost c1;
FunctionCost c1;
if (ptypes.length == 0) {
if (ctor.takesVarArgs()) {
c1= new Cost(source, null, Rank.ELLIPSIS_CONVERSION);
c1= new FunctionCost(ctor, new Cost(source, null, Rank.ELLIPSIS_CONVERSION));
} else {
continue;
}
} else {
IType ptype= ptypes[0];
// We don't need to check the implicit conversion sequence it the type is void
// We don't need to check the implicit conversion sequence if the type is void
if (ptype instanceof ICPPBasicType && ((ICPPBasicType) ptype).getKind() == Kind.eVoid)
continue;
if (ptypes.length > 1) {
@ -397,9 +477,9 @@ public class Conversions {
continue;
}
c1= checkImplicitConversionSequence(sourceIsLValue, source, ptype, UDCMode.noUDC, false);
c1= new FunctionCost(ctor, checkImplicitConversionSequence(ptype, source, sourceIsLValue, UDCMode.noUDC, false));
}
int cmp= c1.compareTo(cost1);
int cmp= c1.compareTo(null, cost1);
if (cmp <= 0) {
cost1= c1;
cost2= new Cost(t, t, Rank.IDENTITY);
@ -421,25 +501,28 @@ public class Conversions {
if (dist >= 0) {
final ICPPFunctionType ft = op.getType();
IType implicitType= CPPSemantics.getImplicitType(op, ft.isConst(), ft.isVolatile());
Cost c1= checkImplicitConversionSequence(sourceIsLValue, source, implicitType, UDCMode.noUDC, false);
int cmp= c1.compareTo(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);
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);
}
}
}
}
}
}
}
if (cost1 == null || cost1.getRank() == Rank.NO_MATCH)
if (cost1 == null || cost1.getCost(0).getRank() == Rank.NO_MATCH)
return null;
return cost2;
@ -449,30 +532,35 @@ public class Conversions {
if (s instanceof ICPPClassType) {
ICPPMethod[] ops = SemanticUtil.getConversionOperators((ICPPClassType) s);
CPPTemplates.instantiateConversionTemplates(ops, target);
Cost cost1= null;
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);
Cost c2= checkImplicitConversionSequence(false, uqReturnType, target, UDCMode.noUDC, false);
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());
Cost c1= checkImplicitConversionSequence(sourceIsLValue, source, implicitType, UDCMode.noUDC, false);
int cmp= c1.compareTo(cost1);
if (cmp <= 0) {
cost1= c1;
cost2= c2;
cost2.setUserDefinedConversion(op);
if (cmp == 0) {
cost2.setAmbiguousUDC(true);
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.getRank() == Rank.NO_MATCH)
if (cost1 == null || cost1.getCost(0).getRank() == Rank.NO_MATCH)
return null;
return cost2;
@ -511,7 +599,6 @@ public class Conversions {
return 1;
}
tbase= getNestedType(tbase, TDEF);
if (tbase instanceof ICPPClassType) {
int n= calculateInheritanceDepth(maxdepth - 1, tbase, ancestorToFind);
if (n > 0)
@ -531,38 +618,31 @@ public class Conversions {
* [4.2] array-to-ptr
* [4.3] function-to-ptr
*/
private static final boolean lvalue_to_rvalue(final Cost cost) throws DOMException {
private static final boolean lvalue_to_rvalue(final Cost cost, boolean isLValue) throws DOMException {
// target should not be a reference here.
boolean isConverted= false;
IType target = getNestedType(cost.target, REF | TDEF);
IType source= getNestedType(cost.source, TDEF);
IType source= getNestedType(cost.source, REF | TDEF);
// 4.1 lvalue to rvalue
IType srcRValue= getNestedType(source, REF | TDEF);
if (source instanceof ICPPReferenceType) {
if (isLValue) {
// 4.1 lvalue of non-function and non-array
if (!(srcRValue instanceof IFunctionType) && !(srcRValue instanceof IArrayType)) {
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(srcRValue, ALLCVQ | TDEF | REF);
IType unqualifiedSrcRValue= getNestedType(source, ALLCVQ | TDEF | REF);
if (unqualifiedSrcRValue instanceof ICPPClassType) {
if (isCompleteType(unqualifiedSrcRValue)) {
source= srcRValue;
} else {
// ill-formed
cost.setRank(Rank.NO_MATCH);
return true;
}
cost.setRank(Rank.NO_MATCH);
return true;
} else {
source= unqualifiedSrcRValue;
}
cost.setRank(Rank.LVALUE_TRANSFORMATION);
isConverted= true;
}
}
// 4.2 array to pointer conversion
if (!isConverted && srcRValue instanceof IArrayType) {
final IArrayType arrayType= (IArrayType) srcRValue;
if (!isConverted && source instanceof IArrayType) {
final IArrayType arrayType= (IArrayType) source;
if (target instanceof IPointerType) {
final IType targetPtrTgt= getNestedType(((IPointerType) target).getType(), TDEF);
@ -579,7 +659,6 @@ public class Conversions {
if (lit.getKind() == IASTLiteralExpression.lk_string_literal) {
source= new CPPPointerType(tmp, false, false);
cost.setQualificationAdjustment(getCVQualifier(targetPtrTgt).isVolatile() ? 2 : 1);
cost.setRank(Rank.LVALUE_TRANSFORMATION);
isConverted= true;
}
}
@ -589,7 +668,6 @@ public class Conversions {
}
if (!isConverted && (target instanceof IPointerType || target instanceof IBasicType)) {
source = new CPPPointerType(getNestedType(arrayType.getType(), TDEF));
cost.setRank(Rank.LVALUE_TRANSFORMATION);
isConverted= true;
}
}
@ -597,9 +675,8 @@ public class Conversions {
// 4.3 function to pointer conversion
if (!isConverted && target instanceof IPointerType) {
final IType targetPtrTgt= getNestedType(((IPointerType) target).getType(), TDEF);
if (targetPtrTgt instanceof IFunctionType && srcRValue instanceof IFunctionType) {
if (targetPtrTgt instanceof IFunctionType && source instanceof IFunctionType) {
source = new CPPPointerType(source);
cost.setRank(Rank.LVALUE_TRANSFORMATION);
isConverted= true;
}
}
@ -849,30 +926,4 @@ public class Conversions {
}
return false;
}
/**
* @param type
* @return whether the specified type has an associated definition
*/
private static final boolean isCompleteType(IType type) {
type= getUltimateType(type, false);
if (type instanceof ICPPTemplateInstance)
return true;
if (type instanceof ICPPClassType) {
if (type instanceof IIndexFragmentBinding) {
try {
return ((IIndexFragmentBinding) type).hasDefinition();
} catch (CoreException e) {
CCorePlugin.log(e);
}
}
try {
return ((ICPPClassType) type).getCompositeScope() != null;
} catch (DOMException e) {
return false;
}
}
return true;
}
}

View file

@ -24,9 +24,12 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPMethod;
*/
final class Cost {
enum Rank {
IDENTITY, LVALUE_TRANSFORMATION, PROMOTION, CONVERSION, CONVERSION_PTR_BOOL,
IDENTITY, PROMOTION, CONVERSION, CONVERSION_PTR_BOOL,
USER_DEFINED_CONVERSION, ELLIPSIS_CONVERSION, NO_MATCH
}
enum ReferenceBinding {
RVALUE_REF_BINDS_RVALUE, LVALUE_REF, OTHER
}
IType source;
IType target;
@ -38,11 +41,13 @@ final class Cost {
private int fQualificationAdjustments;
private int fInheritanceDistance;
private ICPPFunction fUserDefinedConversion;
private ReferenceBinding fReferenceBinding;
public Cost(IType s, IType t, Rank rank) {
source = s;
target = t;
fRank= rank;
fReferenceBinding= ReferenceBinding.OTHER;
}
public Rank getRank() {
@ -53,6 +58,11 @@ final class Cost {
fRank= rank;
}
public void setReferenceBinding(ReferenceBinding binding) {
fReferenceBinding= binding;
}
public boolean isAmbiguousUDC() {
return fAmbiguousUDC;
}
@ -79,9 +89,6 @@ final class Cost {
public void setQualificationAdjustment(int adjustment) {
fQualificationAdjustments= adjustment;
if (adjustment != 0 && fRank == Rank.IDENTITY) {
fRank= Rank.LVALUE_TRANSFORMATION;
}
}
/**
@ -130,6 +137,14 @@ final class Cost {
if (cmp != 0)
return cmp;
if (fReferenceBinding == ReferenceBinding.LVALUE_REF) {
if (other.fReferenceBinding == ReferenceBinding.RVALUE_REF_BINDS_RVALUE)
return 1;
} else if (fReferenceBinding == ReferenceBinding.RVALUE_REF_BINDS_RVALUE) {
if (other.fReferenceBinding == ReferenceBinding.LVALUE_REF)
return -1;
}
int qdiff= fQualificationAdjustments ^ other.fQualificationAdjustments;
if (qdiff != 0) {
if ((fQualificationAdjustments & qdiff) == 0)

View file

@ -33,6 +33,12 @@ class FunctionCost {
fSourceIsLValue= new BitSet(paramCount);
}
public FunctionCost(IFunction fn, Cost cost) {
fFunction= fn;
fCosts= new Cost[] {cost};
fSourceIsLValue= null; // no udc will be performed
}
public int getLength() {
return fCosts.length;
}

View file

@ -14,6 +14,7 @@
*******************************************************************************/
package org.eclipse.cdt.internal.core.dom.parser.cpp.semantics;
import java.util.BitSet;
import java.util.Collections;
import java.util.List;
import java.util.Map;
@ -66,6 +67,7 @@ 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.ICPPASTCompositeTypeSpecifier.ICPPASTBaseSpecifier;
import org.eclipse.cdt.core.parser.util.ArrayUtil;
import org.eclipse.cdt.core.parser.util.CharArrayObjectMap;
@ -108,6 +110,7 @@ public class LookupData {
private Object[] functionArgs;
private IType[] functionArgTypes;
public ProblemBinding problem;
private BitSet functionArgLValues;
public LookupData(IASTName n) {
astName = n;
@ -600,7 +603,7 @@ public class LookupData {
functionArgTypes= new IType[pdecls.length];
for (int i = 0; i < pdecls.length; i++) {
IASTParameterDeclaration p = pdecls[i];
functionArgTypes[i]= CPPVisitor.createType(p.getDeclarator());
functionArgTypes[i]= SemanticUtil.getSimplifiedType(CPPVisitor.createType(p.getDeclarator()));
}
} else if (functionArgs instanceof IASTExpression[]) {
IASTExpression[] exprs= (IASTExpression[]) functionArgs;
@ -608,14 +611,38 @@ public class LookupData {
for (int i = 0; i < exprs.length; i++) {
IASTExpression e = exprs[i];
IType etype= e.getExpressionType();
functionArgTypes[i]= etype;
functionArgTypes[i]= SemanticUtil.getSimplifiedType(etype);
}
}
}
return functionArgTypes;
}
public BitSet getFunctionArgumentLValues() {
if (functionArgLValues == null) {
functionArgLValues= new BitSet();
IASTExpression[] args= getFunctionArguments();
if (args != null) {
for (int i = 0; i < args.length; i++) {
final IASTExpression arg = args[i];
if (arg != null) {
functionArgLValues.set(i, arg.isLValue());
}
}
} else {
IType[] argTypes= getFunctionArgumentTypes();
if (argTypes != null) {
for (int i = 0; i < argTypes.length; i++) {
IType t= argTypes[i];
functionArgLValues.set(i, t instanceof ICPPReferenceType && !((ICPPReferenceType) t).isRValueReference());
}
}
}
}
return functionArgLValues;
}
public void setFunctionArgumentTypes(IType[] paramTypes) {
functionArgTypes= paramTypes;
}

View file

@ -275,8 +275,18 @@ public class SemanticUtil {
return type;
return replaceNestedType((ITypeContainer) atype, newNested);
}
} else if ((options & REF) != 0 && type instanceof ICPPReferenceType) {
t= ((ICPPReferenceType) type).getType();
} else if (type instanceof ICPPReferenceType) {
final ICPPReferenceType rt = (ICPPReferenceType) type;
if ((options & REF) != 0) {
t= rt.getType();
} else if (tdef) {
// a typedef within the reference type can influence whether the reference is lvalue or rvalue
IType nested= rt.getType();
IType newNested = getNestedType(nested, TDEF);
if (nested == newNested)
return type;
return replaceNestedType((ITypeContainer) rt, newNested);
}
}
if (t == null)
return type;
@ -324,6 +334,28 @@ public class SemanticUtil {
return type;
}
static boolean isSimplified(IType type) {
if (type instanceof ICPPFunctionType) {
final ICPPFunctionType ft = (ICPPFunctionType) type;
if (!isSimplified(ft.getReturnType()))
return false;
IType[] ps = ft.getParameterTypes();
for (IType p : ps) {
if (!isSimplified(p))
return false;
}
return true;
}
if (type instanceof ITypedef) {
return false;
}
if (type instanceof ITypeContainer) {
return isSimplified(((ITypeContainer) type).getType());
}
return true;
}
public static IType replaceNestedType(ITypeContainer type, IType newNestedType) {
if (newNestedType == null)
return type;

View file

@ -161,7 +161,7 @@ public class CPPCompositesFactory extends AbstractCompositeFactory {
IType r= rt.getType();
IType r2= getCompositeType(r);
if (r != r2) {
return new CPPReferenceType(r2);
return new CPPReferenceType(r2, rt.isRValueReference());
}
return rt;
}

View file

@ -172,7 +172,7 @@ public class NodeContainer {
declarator.addPointerOperator(new CASTPointer());
break;
case CPP:
declarator.addPointerOperator(new CPPASTReferenceOperator());
declarator.addPointerOperator(new CPPASTReferenceOperator(false));
break;
}
}

View file

@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2006, 2008 IBM Corporation and others.
* Copyright (c) 2006, 2009 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
@ -11,7 +11,6 @@
package org.eclipse.cdt.internal.core.dom.parser.upc.ast;
import org.eclipse.cdt.core.dom.ast.ASTVisitor;
import org.eclipse.cdt.core.dom.ast.IBasicType;
import org.eclipse.cdt.core.dom.ast.IType;
import org.eclipse.cdt.core.dom.ast.IBasicType.Kind;
import org.eclipse.cdt.core.dom.upc.ast.IUPCASTKeywordExpression;
@ -50,6 +49,9 @@ public class UPCASTKeywordExpression extends ASTNode implements IUPCASTKeywordEx
return new CBasicType(Kind.eInt, 0, this);
}
public boolean isLValue() {
return false;
}
@Override
public boolean accept(ASTVisitor visitor) {