mirror of
https://github.com/eclipse-cdt/cdt
synced 2025-08-12 18:55:38 +02:00
Bug 470943 - Binding of rvalue reference to temporary (core issue 1138)
Change-Id: I9524816b279e3f791535b11b54d475cf657fe64b Signed-off-by: Nathan Ridge <zeratul976@hotmail.com>
This commit is contained in:
parent
6730366662
commit
4e90a96767
3 changed files with 164 additions and 119 deletions
|
@ -2389,39 +2389,95 @@ public class AST2CPPSpecTest extends AST2SpecTestBase {
|
||||||
parse(getAboveComment(), ParserLanguage.CPP, true, 0);
|
parse(getAboveComment(), ParserLanguage.CPP, true, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// double d = 2.0;
|
// Note: the examples for 8.5.3/5 are written slightly differently
|
||||||
// double& rd = d; // rd refers to d
|
// than they appear in the standard. In the standard, the examples
|
||||||
// const double& rcd = d; // rcd refers to d
|
// demonstrate the rules with variable initialiation, but CDT doesn't
|
||||||
// struct A { };
|
// currently issue problem bindings for variable initialization,
|
||||||
// struct B : public A { } b;
|
// so in the tests the examples are rewritten to use function calls.
|
||||||
// A& ra = b; // ra refers to A subobject in b
|
|
||||||
// const A& rca = b; // rca refers to A subobject in b
|
// void f1(double);
|
||||||
|
// void f2(double&);
|
||||||
|
// void f3(const double&);
|
||||||
|
// struct A { };
|
||||||
|
// struct B : public A { operator int&(); } b;
|
||||||
|
// void f4(A&);
|
||||||
|
// void f5(const A&);
|
||||||
|
// void f6(int&);
|
||||||
|
// int main() {
|
||||||
|
// f1(2.0);
|
||||||
|
// double d;
|
||||||
|
// f2(d);
|
||||||
|
// f3(d);
|
||||||
|
// f4(b);
|
||||||
|
// f5(b);
|
||||||
|
// f6(B());
|
||||||
|
// }
|
||||||
public void test8_5_3s5a() throws Exception {
|
public void test8_5_3s5a() throws Exception {
|
||||||
parse(getAboveComment(), ParserLanguage.CPP, true, 0);
|
parse(getAboveComment(), ParserLanguage.CPP, true, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// double& rd2 = 2.0; // error: not an lvalue and reference not const
|
// void f1(double&);
|
||||||
// int i = 2;
|
// void f2(double&);
|
||||||
// double& rd3 = i; // error: type mismatch and reference not const
|
// int main() {
|
||||||
|
// f1(2.0); // error: not an lvalue and reference not const
|
||||||
|
// int i = 2;
|
||||||
|
// f2(i); // error: type mismatch and reference not const
|
||||||
|
// }
|
||||||
public void test8_5_3s5b() throws Exception {
|
public void test8_5_3s5b() throws Exception {
|
||||||
parse(getAboveComment(), ParserLanguage.CPP, true, 0);
|
BindingAssertionHelper helper = getAssertionHelper(ParserLanguage.CPP);
|
||||||
|
helper.assertProblem("f1(2", "f1");
|
||||||
|
helper.assertProblem("f2(i", "f2");
|
||||||
}
|
}
|
||||||
|
|
||||||
// struct A { };
|
// struct A { };
|
||||||
// struct B : public A { } b;
|
// struct B : public A { } b;
|
||||||
// extern B f();
|
// extern B f();
|
||||||
// const A& rca = f(); // Either bound to the A subobject of the B rvalue,
|
// void f1(const A&);
|
||||||
// // or the entire B object is copied and the reference
|
// void f2(A&&);
|
||||||
// // is bound to the A subobject of the copy
|
// struct X {
|
||||||
|
// operator B();
|
||||||
|
// operator int&();
|
||||||
|
// } x;
|
||||||
|
// void f3(int&&);
|
||||||
|
// void f4(B&&);
|
||||||
|
// int main() {
|
||||||
|
// f1(f()); // bound to the A subobject of the B rvalue
|
||||||
|
// f2(f()); // same as above
|
||||||
|
// f1(x); // bound to the A subobject of the result of the conversion
|
||||||
|
// f3(static_cast<int&&>(i)); // bound directly to i
|
||||||
|
// f4(x); // bound directly to the result of operator B
|
||||||
|
// f3(X()); // error: lvalue-to-rvalue conversion applied to result of operator int&
|
||||||
|
// }
|
||||||
public void test8_5_3s5c() throws Exception {
|
public void test8_5_3s5c() throws Exception {
|
||||||
parse(getAboveComment(), ParserLanguage.CPP, true, 0);
|
BindingAssertionHelper helper = getAssertionHelper(ParserLanguage.CPP);
|
||||||
|
helper.assertNonProblem("f1(f", "f1");
|
||||||
|
helper.assertNonProblem("f2(f", "f2");
|
||||||
|
helper.assertNonProblem("f1(x", "f1");
|
||||||
|
helper.assertNonProblem("f3(s", "f3");
|
||||||
|
helper.assertNonProblem("f4(x", "f4");
|
||||||
|
helper.assertProblem("f3(X", "f3");
|
||||||
}
|
}
|
||||||
|
|
||||||
// const double& rcd2 = 2; // rcd2 refers to temporary with value 2.0
|
// void f1(const double&);
|
||||||
// const volatile int cvi = 1;
|
// void f2(double&&);
|
||||||
// const int& r = cvi; // error: type qualifiers dropped
|
// void f3(const int&);
|
||||||
|
// int main() {
|
||||||
|
// f1(2);
|
||||||
|
// f2(2);
|
||||||
|
// const volatile int cvi = 1;
|
||||||
|
// f3(cvi); // error: type qualifiers dropped
|
||||||
|
// double d;
|
||||||
|
// int i;
|
||||||
|
// f2(d); // error: copying lvalue of related type
|
||||||
|
// f2(i);
|
||||||
|
// }
|
||||||
public void test8_5_3s5d() throws Exception {
|
public void test8_5_3s5d() throws Exception {
|
||||||
parse(getAboveComment(), ParserLanguage.CPP, true, 0);
|
BindingAssertionHelper helper = getAssertionHelper(ParserLanguage.CPP);
|
||||||
|
helper.assertNonProblem("f1(2", "f1");
|
||||||
|
helper.assertNonProblem("f2(2", "f2");
|
||||||
|
helper.assertProblem("f3(cv", "f3");
|
||||||
|
helper.assertProblem("f2(d)", "f2");
|
||||||
|
helper.assertNonProblem("f2(i", "f2");
|
||||||
}
|
}
|
||||||
|
|
||||||
// struct X { int a; };
|
// struct X { int a; };
|
||||||
|
|
|
@ -8281,7 +8281,7 @@ public class AST2CPPTests extends AST2TestBase {
|
||||||
// caref(b);
|
// caref(b);
|
||||||
// dref(2.0); // error: not an lvalue and reference not const
|
// dref(2.0); // error: not an lvalue and reference not const
|
||||||
// dref(i); // error: type mismatch and reference not const
|
// dref(i); // error: type mismatch and reference not const
|
||||||
// drref(i); // error: rvalue reference cannot bind to lvalue
|
// drref(i); // bound to temporary double object
|
||||||
// caref(f()); // bound to the A subobject of the B rvalue.
|
// caref(f()); // bound to the A subobject of the B rvalue.
|
||||||
// carref(f()); // same as above
|
// carref(f()); // same as above
|
||||||
// caref(x); // bound to the A subobject of the result of the conversion
|
// caref(x); // bound to the A subobject of the result of the conversion
|
||||||
|
@ -8298,7 +8298,7 @@ public class AST2CPPTests extends AST2TestBase {
|
||||||
bh.assertNonProblem("caref(b)", 5);
|
bh.assertNonProblem("caref(b)", 5);
|
||||||
bh.assertProblem("dref(2.0)", 4);
|
bh.assertProblem("dref(2.0)", 4);
|
||||||
bh.assertProblem("dref(i)", 4);
|
bh.assertProblem("dref(i)", 4);
|
||||||
bh.assertProblem("drref(i)", 5);
|
bh.assertNonProblem("drref(i)", 5);
|
||||||
bh.assertNonProblem("caref(f())", 5);
|
bh.assertNonProblem("caref(f())", 5);
|
||||||
bh.assertNonProblem("carref(f())", 6);
|
bh.assertNonProblem("carref(f())", 6);
|
||||||
bh.assertNonProblem("caref(x)", 5);
|
bh.assertNonProblem("caref(x)", 5);
|
||||||
|
@ -11102,6 +11102,16 @@ public class AST2CPPTests extends AST2TestBase {
|
||||||
isParameterSignatureEqual(sd.getDeclarators()[0], "(int&&)");
|
isParameterSignatureEqual(sd.getDeclarators()[0], "(int&&)");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// struct S { S(int); };
|
||||||
|
// void find(S&&);
|
||||||
|
// int main() {
|
||||||
|
// int waldo = 42;
|
||||||
|
// find(waldo);
|
||||||
|
// }
|
||||||
|
public void testRValueReferenceBindingToTemporary_470943() throws Exception {
|
||||||
|
parseAndCheckBindings();
|
||||||
|
}
|
||||||
|
|
||||||
// constexpr int waldo1 = 42;
|
// constexpr int waldo1 = 42;
|
||||||
// constexpr auto waldo2 = 43;
|
// constexpr auto waldo2 = 43;
|
||||||
public void testConstexprVariableIsConst_451091() throws Exception {
|
public void testConstexprVariableIsConst_451091() throws Exception {
|
||||||
|
|
|
@ -153,7 +153,7 @@ public class Conversions {
|
||||||
// 'cv3 T3' (this conversion is selected by enumerating the applicable conversion functions (13.3.1.6)
|
// '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)),
|
// and choosing the best one through overload resolution (13.3)),
|
||||||
if (T2 instanceof ICPPClassType && udc != UDCMode.FORBIDDEN && isReferenceRelated(T1, T2, point) < 0) {
|
if (T2 instanceof ICPPClassType && udc != UDCMode.FORBIDDEN && isReferenceRelated(T1, T2, point) < 0) {
|
||||||
Cost cost= initializationByConversionForDirectReference(cv1T1, cv2T2, (ICPPClassType) T2, true, ctx, point);
|
Cost cost= initializationByConversionForDirectReference(cv1T1, cv2T2, (ICPPClassType) T2, true, false, ctx, point);
|
||||||
if (cost != null) {
|
if (cost != null) {
|
||||||
cost.setReferenceBinding(refBindingType);
|
cost.setReferenceBinding(refBindingType);
|
||||||
return cost;
|
return cost;
|
||||||
|
@ -162,97 +162,65 @@ public class Conversions {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Otherwise, the reference shall be an lvalue reference to a non-volatile const type (i.e., cv1
|
// 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 const), or the reference shall be an rvalue reference.
|
||||||
// shall be an rvalue or have function type.
|
if (isLValueRef && getCVQualifier(cv1T1) != CVQualifier.CONST) {
|
||||||
boolean ok;
|
|
||||||
if (isLValueRef) {
|
|
||||||
ok = getCVQualifier(cv1T1) == CVQualifier.CONST;
|
|
||||||
} else {
|
|
||||||
ok= valueCat.isRValue() || T2 instanceof IFunctionType;
|
|
||||||
}
|
|
||||||
if (!ok) {
|
|
||||||
return Cost.NO_CONVERSION;
|
return Cost.NO_CONVERSION;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If T1 is a function type, then
|
// If the initializer expression is an xvalue, class prvalue, array prvalue, or function lvalue
|
||||||
if (T1 instanceof IFunctionType) {
|
// and 'cv1 T1' is reference-compatible with 'cv2 T2', then the reference is bound to the value
|
||||||
// if T2 is the same type as T1, the reference is bound to the initializer expression lvalue;
|
// of the initializer expression (or the appropriate base class subobject).
|
||||||
if (T2.isSameType(T1)) {
|
if (valueCat == ValueCategory.XVALUE
|
||||||
Cost cost= new Cost(T1, T2, Rank.IDENTITY);
|
|| (valueCat == ValueCategory.PRVALUE && (T2 instanceof ICPPClassType || T2 instanceof IArrayType))
|
||||||
cost.setReferenceBinding(refBindingType);
|
|| (valueCat == ValueCategory.LVALUE && T2 instanceof ICPPFunctionType)) {
|
||||||
return cost;
|
Cost cost = isReferenceCompatible(cv1T1, cv2T2, isImpliedObject, point);
|
||||||
}
|
|
||||||
// if T2 is a class type and the initializer expression can be implicitly converted to an lvalue of
|
|
||||||
// type T1 (this conversion is selected by enumerating the applicable conversion functions (13.3.1.6)
|
|
||||||
// and choosing the best one through overload resolution (13.3)), the reference is bound to the
|
|
||||||
// function lvalue that is the result of the conversion;
|
|
||||||
if (T2 instanceof ICPPClassType) {
|
|
||||||
Cost cost= initializationByConversionForDirectReference(cv1T1, cv2T2, (ICPPClassType) T2, true, ctx, point);
|
|
||||||
if (cost != null) {
|
|
||||||
cost.setReferenceBinding(refBindingType);
|
|
||||||
return cost;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// otherwise, the program is ill-formed.
|
|
||||||
return Cost.NO_CONVERSION;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Otherwise, if T2 is a class type and
|
|
||||||
if (T2 instanceof ICPPClassType) {
|
|
||||||
// ... the initializer expression is an rvalue and 'cv1 T1' is reference-compatible with 'cv2 T2'
|
|
||||||
// ..., then the reference is bound to the initializer expression rvalue in the first case
|
|
||||||
if (valueCat.isRValue()) {
|
|
||||||
Cost cost= isReferenceCompatible(cv1T1, cv2T2, isImpliedObject, point);
|
|
||||||
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 sub-object of the object).
|
|
||||||
if (udc != UDCMode.FORBIDDEN && isReferenceRelated(T1, T2, point) < 0) {
|
|
||||||
Cost cost= initializationByConversionForDirectReference(cv1T1, cv2T2, (ICPPClassType) T2, false, ctx, point);
|
|
||||||
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 (T2 instanceof IArrayType && valueCat.isRValue()) {
|
|
||||||
Cost cost= isReferenceCompatible(cv1T1, cv2T2, isImpliedObject, point);
|
|
||||||
if (cost != null) {
|
if (cost != null) {
|
||||||
cost.setReferenceBinding(refBindingType);
|
cost.setReferenceBinding(refBindingType);
|
||||||
return cost;
|
return cost;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If the initializer expression has class type (i.e. T2 is a class type), where T1 is not
|
||||||
|
// reference-related to T2, and can be implicitly converted to an xvalue, class prvalue,
|
||||||
|
// or function lvalue of type 'cv3 T3', where 'cv1 T1' is reference-compatible with 'cv3 T3',
|
||||||
|
// then the reference is bound to the result of the conversion (or the appropriate base class
|
||||||
|
// subobject). If the reference is an rvalue reference and the second standard conversion
|
||||||
|
// sequence of the user-defined conversion sequence includes an lvalue-to-rvalue
|
||||||
|
// conversion, the program is ill-formed [this is why we pass illFormedIfLValue = true].
|
||||||
|
if (T2 instanceof ICPPClassType) {
|
||||||
|
if (udc != UDCMode.FORBIDDEN && isReferenceRelated(T1, T2, point) < 0) {
|
||||||
|
Cost cost= initializationByConversionForDirectReference(cv1T1, cv2T2, (ICPPClassType) T2, false, true, ctx, point);
|
||||||
|
if (cost != null) {
|
||||||
|
if (cost != Cost.NO_CONVERSION) {
|
||||||
|
cost.setReferenceBinding(refBindingType);
|
||||||
|
}
|
||||||
|
return cost;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Otherwise, a temporary of type 'cv1 T1' is created and initialized from the initializer
|
// 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
|
// 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
|
// bound to the temporary.
|
||||||
// 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
|
// 13.3.3.1.7 no temporary object when converting the implicit object parameter
|
||||||
if (!isImpliedObject && ctx != Context.REQUIRE_DIRECT_BINDING) {
|
if (!isImpliedObject && ctx != Context.REQUIRE_DIRECT_BINDING) {
|
||||||
if (isReferenceRelated(T1, T2, point) < 0 || compareQualifications(cv1T1, cv2T2) >= 0) {
|
Cost cost= nonReferenceConversion(valueCat, cv2T2, T1, udc, point);
|
||||||
Cost cost= nonReferenceConversion(valueCat, cv2T2, T1, udc, point);
|
if (cost.converts()) {
|
||||||
if (cost.converts()) {
|
cost.setReferenceBinding(refBindingType);
|
||||||
cost.setReferenceBinding(refBindingType);
|
|
||||||
}
|
|
||||||
return cost;
|
|
||||||
}
|
}
|
||||||
|
boolean referenceRelated = isReferenceRelated(T1, T2, point) >= 0;
|
||||||
|
// If T1 is reference-related to T2, cv1 shall be the same cv-qualification as,
|
||||||
|
// or greater cv-qualification than, cv2.
|
||||||
|
if (referenceRelated && compareQualifications(cv1T1, cv2T2) < 0) {
|
||||||
|
return Cost.NO_CONVERSION;
|
||||||
|
}
|
||||||
|
// if T1 is reference-related to T2 and the reference is an rvalue reference,
|
||||||
|
// the initializer expression shall not be an lvalue.
|
||||||
|
if (referenceRelated && !isLValueRef && valueCat == ValueCategory.LVALUE) {
|
||||||
|
return Cost.NO_CONVERSION;
|
||||||
|
}
|
||||||
|
return cost;
|
||||||
}
|
}
|
||||||
return Cost.NO_CONVERSION;
|
return Cost.NO_CONVERSION;
|
||||||
}
|
}
|
||||||
|
@ -263,9 +231,15 @@ public class Conversions {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* C++0x: 13.3.1.6 Initialization by conversion function for direct reference binding
|
* C++0x: 13.3.1.6 Initialization by conversion function for direct reference binding
|
||||||
* @param point
|
* @param needLValue don't consider conversion functions that return rvalue references
|
||||||
|
* @param illFormedIfLValue make the conversion ill-formed (by returning Cost.NO_CONVERSION)
|
||||||
|
* if the best match is a conversion function that returns an
|
||||||
|
* lvalue reference
|
||||||
|
* Note that there's a difference between returning null and returning Cost.NO_CONVERSION:
|
||||||
|
* in the former case, the caller will continue trying other conversion methods.
|
||||||
*/
|
*/
|
||||||
private static Cost initializationByConversionForDirectReference(final IType cv1T1, final IType cv2T2, final ICPPClassType T2, boolean needLValue, Context ctx, IASTNode point)
|
private static Cost initializationByConversionForDirectReference(final IType cv1T1, final IType cv2T2, final ICPPClassType T2,
|
||||||
|
boolean needLValue, boolean illFormedIfLValue, Context ctx, IASTNode point)
|
||||||
throws DOMException {
|
throws DOMException {
|
||||||
ICPPMethod[] fcns= SemanticUtil.getConversionOperators(T2, point);
|
ICPPMethod[] fcns= SemanticUtil.getConversionOperators(T2, point);
|
||||||
Cost operatorCost= null;
|
Cost operatorCost= null;
|
||||||
|
@ -281,21 +255,26 @@ public class Conversions {
|
||||||
final ICPPFunctionType ft = op.getType();
|
final ICPPFunctionType ft = op.getType();
|
||||||
IType t= getNestedType(ft.getReturnType(), TDEF);
|
IType t= getNestedType(ft.getReturnType(), TDEF);
|
||||||
final boolean isLValueRef= t instanceof ICPPReferenceType && !((ICPPReferenceType) t).isRValueReference();
|
final boolean isLValueRef= t instanceof ICPPReferenceType && !((ICPPReferenceType) t).isRValueReference();
|
||||||
if (isLValueRef == needLValue) { // require an lvalue or rvalue
|
if (needLValue && !isLValueRef) {
|
||||||
IType implicitParameterType= CPPSemantics.getImplicitParameterType(op);
|
continue;
|
||||||
Cost udcCost= isReferenceCompatible(getNestedType(implicitParameterType, TDEF | REF), cv2T2, true, point); // expression type to implicit object type
|
}
|
||||||
if (udcCost != null) {
|
IType implicitParameterType= CPPSemantics.getImplicitParameterType(op);
|
||||||
// Make sure top-level cv-qualifiers are compared
|
Cost udcCost= isReferenceCompatible(getNestedType(implicitParameterType, TDEF | REF), cv2T2, true, point); // expression type to implicit object type
|
||||||
udcCost.setReferenceBinding(ReferenceBinding.LVALUE_REF);
|
if (udcCost != null) {
|
||||||
FunctionCost udcFuncCost= new FunctionCost(op, udcCost, point);
|
// Make sure top-level cv-qualifiers are compared
|
||||||
int cmp= udcFuncCost.compareTo(null, bestUdcCost);
|
udcCost.setReferenceBinding(ReferenceBinding.LVALUE_REF);
|
||||||
if (cmp <= 0) {
|
FunctionCost udcFuncCost= new FunctionCost(op, udcCost, point);
|
||||||
Cost cost= isReferenceCompatible(cv1T1, getNestedType(t, TDEF | REF), false, point); // converted to target
|
int cmp= udcFuncCost.compareTo(null, bestUdcCost);
|
||||||
if (cost != null) {
|
if (cmp <= 0) {
|
||||||
bestUdcCost= udcFuncCost;
|
Cost cost= isReferenceCompatible(cv1T1, getNestedType(t, TDEF | REF), false, point); // converted to target
|
||||||
ambiguousConversionOperator= cmp == 0;
|
if (cost != null) {
|
||||||
operatorCost= cost;
|
bestUdcCost= udcFuncCost;
|
||||||
operatorCost.setUserDefinedConversion(op);
|
ambiguousConversionOperator= cmp == 0;
|
||||||
|
operatorCost= cost;
|
||||||
|
operatorCost.setUserDefinedConversion(op);
|
||||||
|
|
||||||
|
if (illFormedIfLValue && isLValueRef) {
|
||||||
|
operatorCost = Cost.NO_CONVERSION;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue