1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-07-23 08:55:25 +02:00

Bug 324853: Expression type for conditional expression.

This commit is contained in:
Markus Schorn 2010-09-13 14:45:53 +00:00
parent c5aee0fe78
commit 4c1d5c5347
9 changed files with 603 additions and 186 deletions

View file

@ -18,6 +18,7 @@ import static org.eclipse.cdt.core.dom.ast.IASTExpression.ValueCategory.LVALUE;
import static org.eclipse.cdt.core.dom.ast.IASTExpression.ValueCategory.XVALUE;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.StringReader;
import java.util.Arrays;
import java.util.HashSet;
@ -271,8 +272,17 @@ public class AST2CPPTests extends AST2BaseTest {
assertNoProblemBindings( col );
return tu;
}
protected IASTTranslationUnit parseAndCheckBindings() throws Exception {
String code= getAboveComment();
return parseAndCheckBindings(code);
}
protected BindingAssertionHelper getAssertionHelper() throws ParserException, IOException {
String code= getAboveComment();
return new BindingAssertionHelper(code, true);
}
public void testBug40422() throws Exception
{
IASTTranslationUnit tu = parse( "class A { int y; }; int A::* x = 0;", ParserLanguage.CPP ); //$NON-NLS-1$
@ -4543,7 +4553,7 @@ public class AST2CPPTests extends AST2BaseTest {
// };
// Sub::Sub( Other * b ) : Base(b) {}
public void testBug95673() throws Exception {
BindingAssertionHelper ba= new BindingAssertionHelper(getAboveComment(), true);
BindingAssertionHelper ba= getAssertionHelper();
ICPPConstructor ctor= ba.assertNonProblem("Base( Other", 4, ICPPConstructor.class);
ICPPConstructor ctor2= ba.assertNonProblem("Base(b)", 4, ICPPConstructor.class);
@ -4949,7 +4959,7 @@ public class AST2CPPTests extends AST2BaseTest {
// f1(__null);
// }
public void testBug240567() throws Exception {
BindingAssertionHelper bh= new BindingAssertionHelper(getAboveComment(), true);
BindingAssertionHelper bh= getAssertionHelper();
bh.assertNonProblem("f1(__null", 2, ICPPFunction.class);
}
@ -5298,7 +5308,7 @@ public class AST2CPPTests extends AST2BaseTest {
// problem5(ptm);
// }
public void testBug214335() throws Exception {
BindingAssertionHelper bh= new BindingAssertionHelper(getAboveComment(), true);
BindingAssertionHelper bh= getAssertionHelper();
IBinding b00= bh.assertProblem("problem1(\"", 8);
IBinding b01= bh.assertProblem("problem2(\"", 8);
@ -5416,7 +5426,7 @@ public class AST2CPPTests extends AST2BaseTest {
// a=0;
// }
public void testUsingDirectiveWithNestedClass_Bug209582() throws Exception {
BindingAssertionHelper bh= new BindingAssertionHelper(getAboveComment(), true);
BindingAssertionHelper bh= getAssertionHelper();
IBinding b= bh.assertNonProblem("a=", 1);
assertEquals("x", b.getScope().getScopeName().toString());
@ -5435,7 +5445,7 @@ public class AST2CPPTests extends AST2BaseTest {
// Test foo3 (&bar);
// }
public void testCastAmbiguity_Bug211756() throws Exception {
BindingAssertionHelper bh= new BindingAssertionHelper(getAboveComment(), true);
BindingAssertionHelper bh= getAssertionHelper();
bh.assertNonProblem("foo1", 4);
bh.assertNonProblem("foo2", 4);
@ -5449,7 +5459,7 @@ public class AST2CPPTests extends AST2BaseTest {
// return 0;
// }
public void testTemplateIDAmbiguity_Bug104706() throws Exception {
BindingAssertionHelper bh= new BindingAssertionHelper(getAboveComment(), true);
BindingAssertionHelper bh= getAssertionHelper();
bh.assertNonProblem("relayIndex <", 10);
bh.assertNonProblem("relayIndex >", 10);
@ -5487,7 +5497,7 @@ public class AST2CPPTests extends AST2BaseTest {
// func(unqualified);
// }
public void testScopeOfUsingDelegates_Bug219424() throws Exception {
BindingAssertionHelper bh= new BindingAssertionHelper(getAboveComment(), true);
BindingAssertionHelper bh= getAssertionHelper();
bh.assertNonProblem("cl c", 2);
bh.assertNonProblem("func(qualified)", 4);
@ -5593,7 +5603,7 @@ public class AST2CPPTests extends AST2BaseTest {
// namespace ns { typedef int ns::TINT; } // illegal, still no CCE is expected.
public void testQualifiedTypedefs_Bug222093() throws Exception{
BindingAssertionHelper bh= new BindingAssertionHelper(getAboveComment(), true);
BindingAssertionHelper bh= getAssertionHelper();
IBinding td= bh.assertProblem("TINT", 4);
bh.assertProblem("ns::", 2);
}
@ -5667,7 +5677,7 @@ public class AST2CPPTests extends AST2BaseTest {
// foo/*k2*/(11.1E1L);
// }
public void testLiteralsViaOverloads_225534() throws Exception {
BindingAssertionHelper ba= new BindingAssertionHelper(getAboveComment(), true);
BindingAssertionHelper ba= getAssertionHelper();
char[] cs= {'a','b','e','f','g','h','i','j','k'};
for(char c : cs) {
for(int i=1; i<(c < 'i' ? 4 : 3); i++) {
@ -5727,7 +5737,7 @@ public class AST2CPPTests extends AST2BaseTest {
// X::operator int() {}
// X::xtint(a); // 2
public void testEmptyDeclSpecifier() throws Exception {
BindingAssertionHelper ba= new BindingAssertionHelper(getAboveComment(), true);
BindingAssertionHelper ba= getAssertionHelper();
ba.assertNonProblem("X {", 1, ICPPClassType.class);
ba.assertNonProblem("X()", 1, ICPPConstructor.class);
ba.assertNonProblem("~X", 2, ICPPMethod.class);
@ -5832,7 +5842,7 @@ public class AST2CPPTests extends AST2BaseTest {
// class C;
// void func(void (C::*m)(int) const);
public void test233889_a() throws Exception {
BindingAssertionHelper bh= new BindingAssertionHelper(getAboveComment(), true);
BindingAssertionHelper bh= getAssertionHelper();
ICPPFunction func= bh.assertNonProblem("func(", 4, ICPPFunction.class);
assertEquals(1,func.getParameters().length);
IType type= func.getParameters()[0].getType();
@ -5854,7 +5864,7 @@ public class AST2CPPTests extends AST2BaseTest {
// func(&C::m2);
// }
public void testBug233889_b() throws Exception {
BindingAssertionHelper bh= new BindingAssertionHelper(getAboveComment(), true);
BindingAssertionHelper bh= getAssertionHelper();
ICPPFunction fn1= bh.assertNonProblem("func(&C::m1", 4, ICPPFunction.class);
ICPPFunction fn2= bh.assertNonProblem("func(&C::m2", 4, ICPPFunction.class);
assertNotSame(fn1, fn2);
@ -5875,7 +5885,7 @@ public class AST2CPPTests extends AST2BaseTest {
// void member4() const volatile { foo(this);/*4*/ }
// };
public void testThisType() throws Exception {
BindingAssertionHelper ba=new BindingAssertionHelper(getAboveComment(), true);
BindingAssertionHelper ba=getAssertionHelper();
ICPPFunction pt1= ba.assertNonProblem("foo(this);/*1*/", 3, ICPPFunction.class);
ICPPFunction pt2= ba.assertNonProblem("foo(this);/*2*/", 3, ICPPFunction.class);
ICPPFunction pt3= ba.assertNonProblem("foo(this);/*3*/", 3, ICPPFunction.class);
@ -5904,7 +5914,7 @@ public class AST2CPPTests extends AST2BaseTest {
// a2->foo();/*2*/
// }
public void testMemberAccessOperator_a() throws Exception {
BindingAssertionHelper ba=new BindingAssertionHelper(getAboveComment(), true);
BindingAssertionHelper ba=getAssertionHelper();
ba.assertProblem("foo();/*1*/", 3);
ba.assertNonProblem("foo();/*2*/", 3);
}
@ -5927,7 +5937,7 @@ public class AST2CPPTests extends AST2BaseTest {
// b2->foo();/*2*/
// }
public void testMemberAccessOperator_b() throws Exception {
BindingAssertionHelper ba=new BindingAssertionHelper(getAboveComment(), true);
BindingAssertionHelper ba=getAssertionHelper();
ICPPMethod m1= ba.assertNonProblem("foo();/*1*/", 3, ICPPMethod.class);
ICPPMethod m2= ba.assertNonProblem("foo();/*2*/", 3, ICPPMethod.class);
assertEquals(m1.getClassOwner().getName(), "A");
@ -5943,7 +5953,7 @@ public class AST2CPPTests extends AST2BaseTest {
// c->foo();/**/ // refers to A::foo
// }
public void testMemberAccessOperator_c() throws Exception {
BindingAssertionHelper ba= new BindingAssertionHelper(getAboveComment(), true);
BindingAssertionHelper ba= getAssertionHelper();
ba.assertNonProblem("foo();/**/", 3);
}
@ -5956,7 +5966,7 @@ public class AST2CPPTests extends AST2BaseTest {
// c->foo();/**/ // expect problem - foo is not in B
// }
public void testMemberAccessOperator_d() throws Exception {
BindingAssertionHelper ba= new BindingAssertionHelper(getAboveComment(), true);
BindingAssertionHelper ba= getAssertionHelper();
ba.assertProblem("foo();/**/", 3);
}
@ -5972,7 +5982,7 @@ public class AST2CPPTests extends AST2BaseTest {
// c->foo();/**/ // refers to A::foo
// }
public void testMemberAccessOperator_e() throws Exception {
BindingAssertionHelper ba= new BindingAssertionHelper(getAboveComment(), true);
BindingAssertionHelper ba= getAssertionHelper();
ba.assertNonProblem("foo();/**/", 3);
}
@ -6000,7 +6010,7 @@ public class AST2CPPTests extends AST2BaseTest {
// f4(s);
// }
public void testArrayToPointerConversion() throws Exception {
BindingAssertionHelper ba= new BindingAssertionHelper(getAboveComment(), true);
BindingAssertionHelper ba= getAssertionHelper();
ba.assertNonProblem("f1(p)", 2, ICPPFunction.class);
ba.assertProblem("f2(q)", 2);
ba.assertNonProblem("f3(r)", 2, ICPPFunction.class);
@ -6100,7 +6110,7 @@ public class AST2CPPTests extends AST2BaseTest {
// func(y);
// }
public void testOverloadedFunction_248774() throws Exception {
BindingAssertionHelper helper= new BindingAssertionHelper(getAboveComment(), true);
BindingAssertionHelper helper= getAssertionHelper();
ICPPFunction func1= helper.assertNonProblem("func(x)", 4, ICPPFunction.class);
ICPPFunction func2= helper.assertNonProblem("func(y)", 4, ICPPFunction.class);
assertNotSame(func1, func2);
@ -6119,7 +6129,7 @@ public class AST2CPPTests extends AST2BaseTest {
// func(y[0]);
// }
public void testOverloadedOperator_248803() throws Exception {
BindingAssertionHelper helper= new BindingAssertionHelper(getAboveComment(), true);
BindingAssertionHelper helper= getAssertionHelper();
ICPPFunction func1= helper.assertNonProblem("func(x[0])", 4, ICPPFunction.class);
ICPPFunction func2= helper.assertNonProblem("func(y[0])", 4, ICPPFunction.class);
assertNotSame(func1, func2);
@ -6144,7 +6154,7 @@ public class AST2CPPTests extends AST2BaseTest {
// void m();//5
// };
public void testOverridden_248846() throws Exception {
BindingAssertionHelper helper= new BindingAssertionHelper(getAboveComment(), true);
BindingAssertionHelper helper= getAssertionHelper();
ICPPMethod m0= helper.assertNonProblem("m();//0", 1, ICPPMethod.class);
ICPPMethod m1= helper.assertNonProblem("m();//1", 1, ICPPMethod.class);
ICPPMethod m2= helper.assertNonProblem("m();//2", 1, ICPPMethod.class);
@ -6242,7 +6252,7 @@ public class AST2CPPTests extends AST2BaseTest {
// f(p);
// }
public void testFunctionExtraArgument() throws Exception {
BindingAssertionHelper ba= new BindingAssertionHelper(getAboveComment(), true);
BindingAssertionHelper ba= getAssertionHelper();
ba.assertProblem("f(p)", 1);
}
@ -6367,7 +6377,7 @@ public class AST2CPPTests extends AST2BaseTest {
// int y;
// };
public void testScopeOfClassMember_259460() throws Exception {
BindingAssertionHelper ba= new BindingAssertionHelper(getAboveComment(), true);
BindingAssertionHelper ba= getAssertionHelper();
ba.assertNonProblem("B b", 1, ICPPClassType.class);
ba.assertProblem("B p", 1);
ba.assertProblem("B method", 1);
@ -6386,7 +6396,7 @@ public class AST2CPPTests extends AST2BaseTest {
// };
// };
public void testScopeOfClassMember_259648() throws Exception {
BindingAssertionHelper ba= new BindingAssertionHelper(getAboveComment(), true);
BindingAssertionHelper ba= getAssertionHelper();
ba.assertNonProblem("GREEN)", 5, IEnumerator.class);
ba.assertNonProblem("RED;", 3, IEnumerator.class);
ba.assertProblem("GREEN;", 5);
@ -6404,7 +6414,7 @@ public class AST2CPPTests extends AST2BaseTest {
// func(*b);
// }
public void testSmartPointerReference_259680() throws Exception {
BindingAssertionHelper ba= new BindingAssertionHelper(getAboveComment(), true);
BindingAssertionHelper ba= getAssertionHelper();
ICPPFunction f1= ba.assertNonProblem("func(*a)", 4, ICPPFunction.class);
ICPPFunction f2= ba.assertNonProblem("func(*b)", 4, ICPPFunction.class);
assertNotSame(f1, f2);
@ -6445,7 +6455,7 @@ public class AST2CPPTests extends AST2BaseTest {
// (p1 % p2).a; //5
// }
public void testOverloadedBinaryOperator_259927_1() throws Exception {
BindingAssertionHelper ba= new BindingAssertionHelper(getAboveComment(), true);
BindingAssertionHelper ba= getAssertionHelper();
ba.assertNonProblem("a; //1", 1, ICPPField.class);
ba.assertNonProblem("a; //2", 1, ICPPField.class);
ba.assertNonProblem("a; //3", 1, ICPPField.class);
@ -6474,7 +6484,7 @@ public class AST2CPPTests extends AST2BaseTest {
// (b + i).a; //6
// }
public void testOverloadedBinaryOperator_259927_2() throws Exception {
BindingAssertionHelper ba= new BindingAssertionHelper(getAboveComment(), true);
BindingAssertionHelper ba= getAssertionHelper();
ba.assertNonProblem("a; //1", 1, ICPPField.class);
ba.assertNonProblem("a; //2", 1, ICPPField.class);
ba.assertNonProblem("a; //3", 1, ICPPField.class);
@ -6498,7 +6508,7 @@ public class AST2CPPTests extends AST2BaseTest {
// (++p1).x; //2
// }
public void testOverloadedUnaryOperator_259927_3() throws Exception {
BindingAssertionHelper ba= new BindingAssertionHelper(getAboveComment(), true);
BindingAssertionHelper ba= getAssertionHelper();
ba.assertNonProblem("x; //1", 1, ICPPField.class);
ba.assertNonProblem("x; //2", 1, ICPPField.class);
}
@ -6516,7 +6526,7 @@ public class AST2CPPTests extends AST2BaseTest {
// (++p1).x; //2
// }
public void testOverloadedUnaryOperator_259927_4() throws Exception {
BindingAssertionHelper ba= new BindingAssertionHelper(getAboveComment(), true);
BindingAssertionHelper ba= getAssertionHelper();
ba.assertNonProblem("x; //1", 1, ICPPField.class);
ba.assertNonProblem("x; //2", 1, ICPPField.class);
}
@ -6547,7 +6557,7 @@ public class AST2CPPTests extends AST2BaseTest {
// (~b).xx; // 6
// }
public void testOverloadedUnaryOperator_259927_5() throws Exception {
BindingAssertionHelper ba= new BindingAssertionHelper(getAboveComment(), true);
BindingAssertionHelper ba= getAssertionHelper();
for(int i = 1; i <=6; i++)
ba.assertNonProblem("xx; // "+i, 2, ICPPField.class);
}
@ -6578,7 +6588,7 @@ public class AST2CPPTests extends AST2BaseTest {
// (~b).xx; // 6
//}
public void testOverloadedUnaryOperator_259927_6() throws Exception {
BindingAssertionHelper ba= new BindingAssertionHelper(getAboveComment(), true);
BindingAssertionHelper ba= getAssertionHelper();
for(int i = 1; i <=6; i++)
ba.assertNonProblem("xx; // "+i, 2, ICPPField.class);
}
@ -6599,7 +6609,7 @@ public class AST2CPPTests extends AST2BaseTest {
// typedef int S2 (int(t)); // resolve this ambiguity first
// };
public void testOrderOfAmbiguityResolution_259373() throws Exception {
BindingAssertionHelper ba= new BindingAssertionHelper(getAboveComment(), true);
BindingAssertionHelper ba= getAssertionHelper();
ICPPVariable a= ba.assertNonProblem("a;", 1);
assertInstance(a.getType(), IPointerType.class);
ICPPVariable b= ba.assertNonProblem("b;", 1);
@ -6780,7 +6790,7 @@ public class AST2CPPTests extends AST2BaseTest {
// f(a());
// }
public void testBug263152_1() throws Exception {
BindingAssertionHelper ba= new BindingAssertionHelper(getAboveComment(), true);
BindingAssertionHelper ba= getAssertionHelper();
ba.assertProblem("f(a())", 1);
}
@ -6796,7 +6806,7 @@ public class AST2CPPTests extends AST2BaseTest {
// p.m(a());
// }
public void testBug263152_2() throws Exception {
BindingAssertionHelper ba= new BindingAssertionHelper(getAboveComment(), true);
BindingAssertionHelper ba= getAssertionHelper();
ba.assertNonProblem("m(a())", 1, ICPPMethod.class);
}
@ -6807,7 +6817,7 @@ public class AST2CPPTests extends AST2BaseTest {
// }
// };
public void _testInstanceMemberInStaticMethod_263154() throws Exception {
BindingAssertionHelper ba= new BindingAssertionHelper(getAboveComment(), true);
BindingAssertionHelper ba= getAssertionHelper();
ba.assertProblem("a =", 1);
}
@ -6843,7 +6853,7 @@ public class AST2CPPTests extends AST2BaseTest {
// f(s);
// }
public void testPointerToNonPointerConversion_263159() throws Exception {
BindingAssertionHelper ba= new BindingAssertionHelper(getAboveComment(), true);
BindingAssertionHelper ba= getAssertionHelper();
ba.assertProblem("f(p)", 1);
ba.assertProblem("f(q)", 1);
ba.assertProblem("f(r)", 1);
@ -6860,7 +6870,7 @@ public class AST2CPPTests extends AST2BaseTest {
// fia(0);
// }
public void testNonPointerToPointerConversion_263707() throws Exception {
BindingAssertionHelper ba= new BindingAssertionHelper(getAboveComment(), true);
BindingAssertionHelper ba= getAssertionHelper();
ba.assertProblem("fip(1)", 3);
ba.assertProblem("fia(1)", 3);
ba.assertNonProblem("fip(0)", 3, ICPPFunction.class);
@ -6982,7 +6992,7 @@ public class AST2CPPTests extends AST2BaseTest {
// f(!p);
// }
public void testTypeOfNotExpression_265779() throws Exception {
BindingAssertionHelper ba= new BindingAssertionHelper(getAboveComment(), true);
BindingAssertionHelper ba= getAssertionHelper();
ba.assertNonProblem("f(!p)", 1);
}
@ -7105,7 +7115,7 @@ public class AST2CPPTests extends AST2BaseTest {
// (x + 1.0).b; //3
// }
public void testOverloadResolutionForOperators_Bug266211() throws Exception {
BindingAssertionHelper ba= new BindingAssertionHelper(getAboveComment(), true);
BindingAssertionHelper ba= getAssertionHelper();
ba.assertNonProblem("a; //1", 1, ICPPField.class);
ba.assertNonProblem("a; //2", 1, ICPPField.class);
ba.assertNonProblem("b; //3", 1, ICPPField.class);
@ -7126,7 +7136,7 @@ public class AST2CPPTests extends AST2BaseTest {
// (x + 1.0).a; //2
// }
public void testOverloadResolutionForOperators_Bug268534() throws Exception {
BindingAssertionHelper ba= new BindingAssertionHelper(getAboveComment(), true);
BindingAssertionHelper ba= getAssertionHelper();
ba.assertNonProblem("a; //1", 1, ICPPField.class);
ba.assertNonProblem("a; //2", 1, ICPPField.class);
}
@ -7140,7 +7150,7 @@ public class AST2CPPTests extends AST2BaseTest {
// test(c);
// }
public void testInvalidUserDefinedConversion_Bug269729() throws Exception {
BindingAssertionHelper ba= new BindingAssertionHelper(getAboveComment(), true);
BindingAssertionHelper ba= getAssertionHelper();
ba.assertProblem("test(c)", 4);
}
@ -7174,14 +7184,14 @@ public class AST2CPPTests extends AST2BaseTest {
// struct A;
// A a;
public void testForwardDeclarationAfterUsing_271236() throws Exception {
BindingAssertionHelper ba= new BindingAssertionHelper(getAboveComment(), true);
BindingAssertionHelper ba= getAssertionHelper();
ba.assertNonProblem("A a;", 1, ICPPClassType.class);
}
// template <class T> class Moo;
// bool getFile(Moo <class Foo> & res);
public void testScopeOfClassFwdDecl_270831() throws Exception {
BindingAssertionHelper ba= new BindingAssertionHelper(getAboveComment(), true);
BindingAssertionHelper ba= getAssertionHelper();
ICPPClassType t= ba.assertNonProblem("Foo", 3, ICPPClassType.class);
IScope scope= t.getScope();
assertEquals(EScopeKind.eGlobal, scope.getKind());
@ -7349,7 +7359,7 @@ public class AST2CPPTests extends AST2BaseTest {
// f(l1);
// }
public void testEnumToIntConversion_285368() throws Exception {
BindingAssertionHelper ba= new BindingAssertionHelper(getAboveComment(), true);
BindingAssertionHelper ba= getAssertionHelper();
ICPPFunction f1 = ba.assertNonProblem("f(i1)", 1, ICPPFunction.class);
IType t1 = f1.getType().getParameterTypes()[0];
assertTrue(t1 instanceof ICPPBasicType);
@ -7369,7 +7379,7 @@ public class AST2CPPTests extends AST2BaseTest {
// typedef enum enum_name enum_name;
public void testTypedefRecursion_285457() throws Exception {
BindingAssertionHelper ba= new BindingAssertionHelper(getAboveComment(), true);
BindingAssertionHelper ba= getAssertionHelper();
ba.assertProblem("enum_name", 9);
}
@ -8650,7 +8660,7 @@ public class AST2CPPTests extends AST2BaseTest {
// Y* m(Y*);//3
// };
public void testOverrideSimpleCovariance_Bug321617() throws Exception {
BindingAssertionHelper helper= new BindingAssertionHelper(getAboveComment(), true);
BindingAssertionHelper helper= getAssertionHelper();
ICPPMethod m0= helper.assertNonProblem("m();//0", 1, ICPPMethod.class);
ICPPMethod m1= helper.assertNonProblem("m(X*);//1", 1, ICPPMethod.class);
ICPPMethod m2= helper.assertNonProblem("m();//2", 1, ICPPMethod.class);
@ -9071,7 +9081,41 @@ public class AST2CPPTests extends AST2BaseTest {
// }
// int j = A::i;
public void testInlineNamespaceLookup_324096() throws Exception {
String code= getAboveComment();
parseAndCheckBindings(code);
parseAndCheckBindings();
}
// struct C {
// operator int();
// };
// void f(C);
// void f(int);
// void test() {
// C c;
// f(true ? c : 1); // calls f(int), not f(C);
// }
public void testConditionalOperator_324853a() throws Exception {
BindingAssertionHelper bh= getAssertionHelper();
IBinding f = bh.assertNonProblem("f(int);", 1);
IBinding ref= bh.assertNonProblem("f(true ? c : 1)", 1);
assertSame(f, ref);
}
// void f(char*);
// void f(const char*);
// void g(char*);
// void test(char* p, const char* cp) {
// f(0 ? cp : p);
// f(0 ? p : ""); // uses f(const char*);
// g(0 ? p : ""); // converts "" to char*
// }
public void testConditionalOperator_324853b() throws Exception {
BindingAssertionHelper bh= getAssertionHelper();
IBinding fc = bh.assertNonProblem("f(const char*);", 1);
IBinding ref;
ref= bh.assertNonProblem("f(0 ? cp : p)", 1);
assertSame(fc, ref);
ref= bh.assertNonProblem("f(0 ? p : \"\")", 1); // "" converted to char*
assertSame(fc, ref);
bh.assertNonProblem("g(0 ? p : \"\")", 1); //
}
}

View file

@ -13,22 +13,43 @@ package org.eclipse.cdt.internal.core.dom.parser.cpp;
import static org.eclipse.cdt.core.dom.ast.IASTExpression.ValueCategory.LVALUE;
import static org.eclipse.cdt.core.dom.ast.IASTExpression.ValueCategory.PRVALUE;
import static org.eclipse.cdt.core.dom.ast.IASTExpression.ValueCategory.XVALUE;
import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.*;
import org.eclipse.cdt.core.dom.ast.ASTVisitor;
import org.eclipse.cdt.core.dom.ast.DOMException;
import org.eclipse.cdt.core.dom.ast.IASTBinaryExpression;
import org.eclipse.cdt.core.dom.ast.IASTConditionalExpression;
import org.eclipse.cdt.core.dom.ast.IASTExpression;
import org.eclipse.cdt.core.dom.ast.IASTNode;
import org.eclipse.cdt.core.dom.ast.IPointerType;
import org.eclipse.cdt.core.dom.ast.IASTUnaryExpression;
import org.eclipse.cdt.core.dom.ast.IBasicType.Kind;
import org.eclipse.cdt.core.dom.ast.IProblemBinding;
import org.eclipse.cdt.core.dom.ast.IType;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPBasicType;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassType;
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.ProblemBinding;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPSemantics;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CVQualifier;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.Conversions;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.Conversions.Context;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.Conversions.UDCMode;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.Cost;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.Cost.Rank;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.ExpressionTypes;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil;
public class CPPASTConditionalExpression extends ASTNode implements IASTConditionalExpression,
IASTAmbiguityParent {
private IASTExpression condition;
private IASTExpression negative;
private IASTExpression positive;
private IASTExpression fCondition;
private IASTExpression fPositive;
private IASTExpression fNegative;
private IType fType;
private ValueCategory fValueCategory;
public CPPASTConditionalExpression() {
@ -43,20 +64,20 @@ public class CPPASTConditionalExpression extends ASTNode implements IASTConditio
public CPPASTConditionalExpression copy() {
CPPASTConditionalExpression copy = new CPPASTConditionalExpression();
copy.setLogicalConditionExpression(condition == null ? null : condition.copy());
copy.setPositiveResultExpression(positive == null ? null : positive.copy());
copy.setNegativeResultExpression(negative == null ? null : negative.copy());
copy.setLogicalConditionExpression(fCondition == null ? null : fCondition.copy());
copy.setPositiveResultExpression(fPositive == null ? null : fPositive.copy());
copy.setNegativeResultExpression(fNegative == null ? null : fNegative.copy());
copy.setOffsetAndLength(this);
return copy;
}
public IASTExpression getLogicalConditionExpression() {
return condition;
return fCondition;
}
public void setLogicalConditionExpression(IASTExpression expression) {
assertNotFrozen();
condition = expression;
fCondition = expression;
if (expression != null) {
expression.setParent(this);
expression.setPropertyInParent(LOGICAL_CONDITION);
@ -64,12 +85,12 @@ public class CPPASTConditionalExpression extends ASTNode implements IASTConditio
}
public IASTExpression getPositiveResultExpression() {
return positive;
return fPositive;
}
public void setPositiveResultExpression(IASTExpression expression) {
assertNotFrozen();
this.positive = expression;
this.fPositive = expression;
if (expression != null) {
expression.setParent(this);
expression.setPropertyInParent(POSITIVE_RESULT);
@ -77,12 +98,12 @@ public class CPPASTConditionalExpression extends ASTNode implements IASTConditio
}
public IASTExpression getNegativeResultExpression() {
return negative;
return fNegative;
}
public void setNegativeResultExpression(IASTExpression expression) {
assertNotFrozen();
this.negative = expression;
this.fNegative = expression;
if (expression != null) {
expression.setParent(this);
expression.setPropertyInParent(NEGATIVE_RESULT);
@ -99,60 +120,230 @@ public class CPPASTConditionalExpression extends ASTNode implements IASTConditio
}
}
if( condition != null ) if( !condition.accept( action ) ) return false;
if( positive != null ) if( !positive.accept( action ) ) return false;
if( negative != null ) if( !negative.accept( action ) ) return false;
if (fCondition != null && !fCondition.accept(action))
return false;
if (fPositive != null && !fPositive.accept(action))
return false;
if (fNegative != null && !fNegative.accept(action))
return false;
if( action.shouldVisitExpressions ){
switch( action.leave( this ) ){
case ASTVisitor.PROCESS_ABORT : return false;
case ASTVisitor.PROCESS_SKIP : return true;
default : break;
}
}
if (action.shouldVisitExpressions && action.leave(this) == ASTVisitor.PROCESS_ABORT)
return false;
return true;
}
public void replace(IASTNode child, IASTNode other) {
if( child == condition )
{
other.setPropertyInParent( child.getPropertyInParent() );
other.setParent( child.getParent() );
condition = (IASTExpression) other;
}
if( child == positive )
{
other.setPropertyInParent( child.getPropertyInParent() );
other.setParent( child.getParent() );
positive = (IASTExpression) other;
}
if( child == negative )
{
other.setPropertyInParent( child.getPropertyInParent() );
other.setParent( child.getParent() );
negative = (IASTExpression) other;
}
public void replace(IASTNode child, IASTNode other) {
if (child == fCondition) {
other.setPropertyInParent(child.getPropertyInParent());
other.setParent(child.getParent());
fCondition = (IASTExpression) other;
}
if (child == fPositive) {
other.setPropertyInParent(child.getPropertyInParent());
other.setParent(child.getParent());
fPositive = (IASTExpression) other;
}
if (child == fNegative) {
other.setPropertyInParent(child.getPropertyInParent());
other.setParent(child.getParent());
fNegative = (IASTExpression) other;
}
}
public IType getExpressionType() {
evaluate();
return fType;
}
// mstodo conditional operator (type)
public IType getExpressionType() {
IASTExpression positiveExpression = getPositiveResultExpression();
if (positiveExpression == null) {
positiveExpression= getLogicalConditionExpression();
}
IType t2 = positiveExpression.getExpressionType();
IType t3 = getNegativeResultExpression().getExpressionType();
if (t3 instanceof IPointerType || t2 == null)
return t3;
return t2;
}
// mstodo conditional operator (value category)
public ValueCategory getValueCategory() {
return PRVALUE;
evaluate();
return fValueCategory;
}
public boolean isLValue() {
return getValueCategory() == LVALUE;
}
private void evaluate() {
if (fValueCategory != null)
return;
fValueCategory= PRVALUE;
// Gnu-extension: Empty positive expression is replaced by condition.
IASTExpression expr2 = getPositiveResultExpression();
final IASTExpression expr3 = getNegativeResultExpression();
if (expr2 == null) {
expr2= getLogicalConditionExpression();
}
IType t2 = expr2.getExpressionType();
IType t3 = expr3.getExpressionType();
if (t2 == null || t3 == null)
return;
final IType uqt2= getNestedType(t2, TDEF | REF | CVTYPE);
final IType uqt3= getNestedType(t3, TDEF | REF | CVTYPE);
if (uqt2 instanceof IProblemBinding || uqt2 instanceof ICPPUnknownType) {
fType= uqt2;
return;
}
if (uqt3 instanceof IProblemBinding || uqt3 instanceof ICPPUnknownType) {
fType= uqt3;
return;
}
final boolean void2= isVoidType(uqt2);
final boolean void3= isVoidType(uqt3);
// Void types: Either both are void or one is a throw expression.
if (void2 || void3) {
if (isThrowExpression(expr2)) {
fType= Conversions.lvalue_to_rvalue(t3);
} else if (isThrowExpression(expr3)) {
fType= Conversions.lvalue_to_rvalue(t2);
} else if (void2 && void3) {
fType= uqt2;
} else {
createProblem();
}
return;
}
final ValueCategory vcat2= expr2.getValueCategory();
final ValueCategory vcat3= expr3.getValueCategory();
final boolean isClassType2 = uqt2 instanceof ICPPClassType;
final boolean isClassType3 = uqt3 instanceof ICPPClassType;
// Same type and same value category
if (t2.isSameType(t3)) {
if (vcat2 == vcat3) {
fType= t2;
fValueCategory= vcat2;
return;
}
} else {
// Different types with at least one class type
if (isClassType2 || isClassType3) {
final Cost cost2= convertToMatch(t2, vcat2, uqt2, t3, vcat3, uqt3); // sets fType and fValueCategory
final Cost cost3= convertToMatch(t3, vcat3, uqt3, t2, vcat2, uqt2); // sets fType and fValueCategory
if (cost2.converts() || cost3.converts()) {
if (cost2.converts()) {
if (cost3.converts() || cost2.isAmbiguousUDC()) {
fType= createProblem();
}
} else if (cost3.isAmbiguousUDC()) {
fType= createProblem();
}
return;
}
} else if (vcat2 == vcat3 && vcat2.isGLValue() && uqt2.isSameType(uqt3)) {
// Two lvalues or two xvalues with same type up to qualification.
final CVQualifier cv2 = SemanticUtil.getCVQualifier(t2);
final CVQualifier cv3 = SemanticUtil.getCVQualifier(t3);
if (cv2.isAtLeastAsQualifiedAs(cv3)) {
fType= t2;
fValueCategory= vcat2;
} else if (cv3.isAtLeastAsQualifiedAs(cv2)) {
fType= t3;
fValueCategory= vcat3;
} else {
createProblem();
}
return;
}
}
// 5.16-5: At least one class type but no conversion
if (isClassType2 || isClassType3) {
ICPPFunction builtin = CPPSemantics.findOverloadedConditionalOperator(expr2, expr3);
if (builtin != null) {
fType= ExpressionTypes.typeFromFunctionCall(builtin);
}
createProblem();
return;
}
// 5.16-6
t2= Conversions.lvalue_to_rvalue(t2);
t3= Conversions.lvalue_to_rvalue(t3);
if (t2.isSameType(t3)) {
fType= t2;
} else {
fType= CPPArithmeticConversion.convertCppOperandTypes(IASTBinaryExpression.op_plus, t2, t3);
if (fType == null) {
fType= Conversions.compositePointerType(t2, t3);
if (fType == null) {
createProblem();
}
}
}
}
private boolean isThrowExpression(IASTExpression expr) {
while (expr instanceof IASTUnaryExpression) {
final IASTUnaryExpression unaryExpr = (IASTUnaryExpression) expr;
final int op = unaryExpr.getOperator();
if (op == IASTUnaryExpression.op_throw) {
return true;
} else if (op == IASTUnaryExpression.op_bracketedPrimary) {
expr= unaryExpr.getOperand();
} else {
return false;
}
}
return false;
}
private Cost convertToMatch(IType t1, ValueCategory vcat1, IType uqt1, IType t2, ValueCategory vcat2, IType uqt2) {
// E2 is an lvalue or E2 is an xvalue
try {
if (vcat2.isGLValue()) {
IType target= new CPPReferenceType(t2, vcat2 == XVALUE);
Cost c= Conversions.checkImplicitConversionSequence(target, t1, vcat1, UDCMode.ALLOWED, Context.REQUIRE_DIRECT_BINDING);
if (c.converts()) {
fType= t2;
fValueCategory= vcat2;
return c;
}
}
// Both are class types and one derives from the other
if (uqt1 instanceof ICPPClassType && uqt2 instanceof ICPPClassType) {
int dist= SemanticUtil.calculateInheritanceDepth(uqt1, uqt2);
if (dist >= 0) {
CVQualifier cv1 = SemanticUtil.getCVQualifier(t1);
CVQualifier cv2 = SemanticUtil.getCVQualifier(t2);
if (cv2.isAtLeastAsQualifiedAs(cv1)) {
fType= t2;
fValueCategory= PRVALUE;
return new Cost(t1, t2, Rank.IDENTITY);
}
return Cost.NO_CONVERSION;
}
if (SemanticUtil.calculateInheritanceDepth(uqt2, uqt1) >= 0)
return Cost.NO_CONVERSION;
}
// Unrelated class types or just one class:
if (vcat2 != PRVALUE) {
t2= Conversions.lvalue_to_rvalue(t2);
}
Cost c= Conversions.checkImplicitConversionSequence(t2, t1, vcat1, UDCMode.ALLOWED, Context.ORDINARY);
if (c.converts()) {
fType= t2;
fValueCategory= PRVALUE;
return c;
}
} catch (DOMException e) {
}
return Cost.NO_CONVERSION;
}
private ProblemBinding createProblem() {
return new ProblemBinding(this, IProblemBinding.SEMANTIC_INVALID_TYPE, this.getRawSignature().toCharArray());
}
private boolean isVoidType(IType t) {
return t instanceof ICPPBasicType && ((ICPPBasicType) t).getKind() == Kind.eVoid;
}
}

View file

@ -2588,7 +2588,7 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
simpleType= IASTSimpleDeclSpecifier.t_decltype;
consume(IToken.t_decltype);
consume(IToken.tLPAREN);
typeofExpression= unaryExpression(CastExprCtx.eNotBExpr);
typeofExpression= expression();
endOffset= consumeOrEOC(IToken.tRPAREN).getEndOffset();
encounteredTypename= true;

View file

@ -70,7 +70,12 @@ public enum OverloadableOperator {
NEW("new"),
DELETE_ARRAY("delete[]"),
DELETE("delete"),
NEW_ARRAY("new[]");
NEW_ARRAY("new[]"),
/**
* Cannot be overloaded by the user, however overload resolution needs to be performed.
*/
CONDITIONAL_OPERATOR("?");
private final char[] rep;

View file

@ -33,6 +33,7 @@ import org.eclipse.cdt.core.dom.ast.IProblemBinding;
import org.eclipse.cdt.core.dom.ast.IScope;
import org.eclipse.cdt.core.dom.ast.IType;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassType;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPEnumeration;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPFunction;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPFunctionType;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPMethod;
@ -217,6 +218,11 @@ class BuiltinOperators {
case NOT:
addFunction(BOOL, BOOL);
break;
case CONDITIONAL_OPERATOR:
binaryPromotedArithmetic(true, ReturnType.CONVERT);
conditional();
break;
}
if (fResult == null)
@ -516,6 +522,19 @@ class BuiltinOperators {
}
}
// 13.6-25
private void conditional() {
for (int i = FIRST; i <= SECOND; i++) {
IType[] types= getClassConversionTypes(i);
for (IType type : types) {
type= SemanticUtil.getNestedType(type, TDEF|REF|CVTYPE);
if (isPointer(type) || isScopedEnumeration(type) || isPointerToMember(type)) {
addFunction(type, type, type);
}
}
}
}
private void addFunction(IType returnType, IType p1) {
addFunction(returnType, new IType[] {p1});
}
@ -556,7 +575,11 @@ class BuiltinOperators {
private boolean isEnumeration(IType type) {
return type instanceof IEnumeration;
}
private boolean isScopedEnumeration(IType type) {
return type instanceof ICPPEnumeration && ((ICPPEnumeration) type).isScoped();
}
private boolean isPointer(IType type) {
return type instanceof IPointerType && !(type instanceof ICPPPointerToMemberType);
}

View file

@ -2825,7 +2825,7 @@ public class CPPSemantics {
*/
IASTExpression arg = createArgForType(fieldReference, type);
ICPPFunction op = findOverloadedOperator(fieldReference, new IASTExpression[] {arg}, uTemp, OverloadableOperator.ARROW, NonMemberMode.none);
ICPPFunction op = findOverloadedOperator(fieldReference, new IASTExpression[] {arg}, uTemp, OverloadableOperator.ARROW, LookupMode.NO_GLOBALS);
if (op == null)
break;
@ -2852,7 +2852,7 @@ public class CPPSemantics {
IASTInitializerClause[] args = {exp.getArrayExpression(), exp.getArgument()};
IType type = exp.getArrayExpression().getExpressionType();
type = SemanticUtil.getUltimateTypeUptoPointers(type);
return findOverloadedOperator(exp, args, type, OverloadableOperator.BRACKET, NonMemberMode.none);
return findOverloadedOperator(exp, args, type, OverloadableOperator.BRACKET, LookupMode.NO_GLOBALS);
}
public static ICPPFunction findOverloadedOperator(IASTFunctionCallExpression exp, ICPPClassType type) {
@ -2864,7 +2864,7 @@ public class CPPSemantics {
}
args = argsToPass.toArray(new IASTInitializerClause[argsToPass.size()]);
return findOverloadedOperator(exp, args, type, OverloadableOperator.PAREN, NonMemberMode.none);
return findOverloadedOperator(exp, args, type, OverloadableOperator.PAREN, LookupMode.NO_GLOBALS);
}
public static ICPPFunction findOverloadedOperator(ICPPASTNewExpression exp) {
@ -2888,14 +2888,14 @@ public class CPPSemantics {
}
}
IASTInitializerClause[] argArray = args.toArray(new IASTInitializerClause[args.size()]);
return findOverloadedOperator(exp, argArray, type, op, NonMemberMode.all);
return findOverloadedOperator(exp, argArray, type, op, LookupMode.ALL_GLOBALS);
}
public static ICPPFunction findOverloadedOperator(ICPPASTDeleteExpression exp) {
OverloadableOperator op = OverloadableOperator.fromDeleteExpression(exp);
IType classType = getNestedClassType(exp);
IASTExpression[] args = new IASTExpression[] {createArgForType(exp, classType)};
return findOverloadedOperator(exp, args, classType, op, NonMemberMode.all);
return findOverloadedOperator(exp, args, classType, op, LookupMode.ALL_GLOBALS);
}
private static ICPPClassType getNestedClassType(ICPPASTDeleteExpression exp) {
@ -3063,7 +3063,7 @@ public class CPPSemantics {
if (!isUserDefined(type))
return null;
return findOverloadedOperator(exp, args, type, op, NonMemberMode.limited);
return findOverloadedOperator(exp, args, type, op, LookupMode.LIMITED_GLOBALS);
}
public static ICPPFunction findOverloadedOperator(IASTBinaryExpression exp) {
@ -3081,14 +3081,25 @@ public class CPPSemantics {
if (!isUserDefined(op1type) && !isUserDefined(op2type))
return null;
IASTExpression[] args = new IASTExpression[] { op1, op2 };
NonMemberMode lookupNonMember = NonMemberMode.none;
if (exp.getOperator() != IASTBinaryExpression.op_assign) {
lookupNonMember= NonMemberMode.limited;
final IASTExpression[] args = new IASTExpression[] { op1, op2 };
final LookupMode lookupNonMember;
if (exp.getOperator() == IASTBinaryExpression.op_assign) {
lookupNonMember = LookupMode.NO_GLOBALS;
} else {
lookupNonMember= LookupMode.LIMITED_GLOBALS;
}
return findOverloadedOperator(exp, args, op1type, op, lookupNonMember);
}
/**
* For simplicity returns an operator of form RT (T, T) rather than RT (boolean, T, T)
*/
public static ICPPFunction findOverloadedConditionalOperator(IASTExpression positive, IASTExpression negative) {
final IASTExpression parent = (IASTExpression) positive.getParent();
final IASTExpression[] args = new IASTExpression[] {positive, negative};
return findOverloadedOperator(parent, args, null,
OverloadableOperator.CONDITIONAL_OPERATOR, LookupMode.NO_GLOBALS);
}
/**
* Returns the operator,() function that would apply to the two given arguments.
@ -3106,12 +3117,12 @@ public class CPPSemantics {
dummy.setParent(first);
IASTExpression[] args = new IASTExpression[] { dummy , second };
return findOverloadedOperator(dummy, args, lookupType, OverloadableOperator.COMMA, NonMemberMode.limited);
return findOverloadedOperator(dummy, args, lookupType, OverloadableOperator.COMMA, LookupMode.LIMITED_GLOBALS);
}
private static enum NonMemberMode {none, limited, all}
private static enum LookupMode {NO_GLOBALS, LIMITED_GLOBALS, ALL_GLOBALS}
private static ICPPFunction findOverloadedOperator(IASTExpression parent, IASTInitializerClause[] args, IType methodLookupType,
OverloadableOperator operator, NonMemberMode mode) {
OverloadableOperator operator, LookupMode mode) {
ICPPClassType callToObjectOfClassType= null;
IType type2= null;
if (args.length >= 2 && args[1] instanceof IASTExpression) {
@ -3158,9 +3169,9 @@ public class CPPSemantics {
LookupData funcData = new LookupData(funcName);
funcData.setFunctionArguments(true, args);
funcData.ignoreMembers = true; // (13.3.1.2.3)
if (mode != NonMemberMode.none || callToObjectOfClassType != null) {
if (mode != LookupMode.NO_GLOBALS || callToObjectOfClassType != null) {
try {
if (mode != NonMemberMode.none) {
if (mode != LookupMode.NO_GLOBALS) {
IScope scope = CPPVisitor.getContainingScope(parent);
if (scope == null)
return null;
@ -3195,7 +3206,7 @@ public class CPPSemantics {
// 13.3.1.2.3
// However, if no operand type has class type, only those non-member functions ...
if (mode == NonMemberMode.limited) {
if (mode == LookupMode.LIMITED_GLOBALS) {
if (funcData.foundItems != null && !(methodLookupType instanceof ICPPClassType) && !(type2 instanceof ICPPClassType)) {
IEnumeration enum1= null;
IEnumeration enum2= null;

View file

@ -50,11 +50,13 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateArgument;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateInstance;
import org.eclipse.cdt.core.parser.util.CharArrayUtils;
import org.eclipse.cdt.internal.core.dom.parser.ArithmeticConversion;
import org.eclipse.cdt.internal.core.dom.parser.ITypeContainer;
import org.eclipse.cdt.internal.core.dom.parser.Value;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTName;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPBasicType;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPPointerToMemberType;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPPointerType;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPQualifierType;
import org.eclipse.cdt.internal.core.dom.parser.cpp.ClassTypeHelper;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.Cost.DeferredUDC;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.Cost.Rank;
@ -64,8 +66,8 @@ import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.Cost.ReferenceBind
* Routines for calculating the cost of conversions.
*/
public class Conversions {
enum UDCMode {ALLOWED, FORBIDDEN, DEFER}
enum Context {ORDINARY, IMPLICIT_OBJECT, FIRST_PARAM_OF_DIRECT_COPY_CTOR}
public enum UDCMode {ALLOWED, FORBIDDEN, DEFER}
public enum Context {ORDINARY, IMPLICIT_OBJECT, FIRST_PARAM_OF_DIRECT_COPY_CTOR, REQUIRE_DIRECT_BINDING}
private static final char[] INITIALIZER_LIST_NAME = "initializer_list".toCharArray(); //$NON-NLS-1$
private static final char[] STD_NAME = "std".toCharArray(); //$NON-NLS-1$
@ -221,7 +223,7 @@ public class Conversions {
// 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) {
if (!isImpliedObject && ctx != Context.REQUIRE_DIRECT_BINDING) {
if (isReferenceRelated(T1, T2) < 0 || compareQualifications(cv1T1, cv2T2) >= 0) {
Cost cost= nonReferenceConversion(valueCat, cv2T2, T1, udc, false);
if (!isImplicitWithoutRefQualifier && cost.converts()) {
@ -808,38 +810,25 @@ public class Conversions {
// 4.2 array to pointer conversion
if (source instanceof IArrayType) {
final IArrayType arrayType= (IArrayType) source;
boolean isConverted= false;
if (target instanceof IPointerType) {
final IType targetPtrTgt= getNestedType(((IPointerType) target).getType(), TDEF);
// 4.2-2 a string literal can be converted to pointer to char
if (!(targetPtrTgt instanceof IQualifierType) || !((IQualifierType) targetPtrTgt).isConst()) {
IType tmp= arrayType.getType();
if (tmp instanceof IQualifierType && ((IQualifierType) tmp).isConst()) {
tmp= ((IQualifierType) tmp).getType();
if (tmp instanceof CPPBasicType) {
IASTExpression val = ((CPPBasicType) tmp).getCreatedFromExpression();
if (val instanceof IASTLiteralExpression) {
IASTLiteralExpression lit= (IASTLiteralExpression) val;
if (lit.getKind() == IASTLiteralExpression.lk_string_literal) {
source= new CPPPointerType(tmp, false, false);
cost.setQualificationAdjustment(getCVQualifier(targetPtrTgt).isVolatile() ? 2 : 1);
isConverted= true;
}
}
}
}
}
source = unqualifyStringLiteral(source, (IPointerType) target, cost);
}
if (!isConverted) {
source = new CPPPointerType(getNestedType(arrayType.getType(), TDEF));
if (!(source instanceof IPointerType)) {
source = new CPPPointerType(getNestedType(((IArrayType) source).getType(), TDEF));
}
} else if (source instanceof IFunctionType) {
// 4.3 function to pointer conversion
source = new CPPPointerType(source);
} else {
if (source instanceof IPointerType) {
// A string literal may have been converted to a pointer when
// computing the type of a conditional expression.
if (target instanceof IPointerType) {
// 4.2-2 a string literal can be converted to pointer to char
source = unqualifyStringLiteral(source, (IPointerType) target, cost);
}
}
source = getNestedType(source, TDEF | REF | ALLCVQ);
}
@ -851,6 +840,35 @@ public class Conversions {
cost.target= target;
return source.isSameType(target);
}
private static IType unqualifyStringLiteral(IType source, final IPointerType target, final Cost cost) {
if (target instanceof ICPPPointerToMemberType)
return source;
final IType targetPtrTgt= getNestedType((target).getType(), TDEF);
if (targetPtrTgt instanceof IQualifierType && ((IQualifierType) targetPtrTgt).isConst())
return source;
IType srcTarget= ((ITypeContainer) source).getType();
if (!(srcTarget instanceof IQualifierType))
return source;
final IQualifierType srcQTarget= (IQualifierType) srcTarget;
if (srcQTarget.isConst() && !srcQTarget.isVolatile()) {
srcTarget= srcQTarget.getType();
if (srcTarget instanceof CPPBasicType) {
IASTExpression val = ((CPPBasicType) srcTarget).getCreatedFromExpression();
if (val instanceof IASTLiteralExpression) {
IASTLiteralExpression lit= (IASTLiteralExpression) val;
if (lit.getKind() == IASTLiteralExpression.lk_string_literal) {
source= new CPPPointerType(srcTarget, false, false);
cost.setQualificationAdjustment(getCVQualifier(targetPtrTgt).isVolatile() ? 2 : 1);
}
}
}
}
return source;
}
/**
* [4.4] Qualifications
@ -870,22 +888,12 @@ public class Conversions {
final int cmp= compareQualifications(t, s); // is t more qualified than s?
if (cmp < 0 || (cmp > 0 && !constInEveryCV2k)) {
return false;
} else {
final boolean sIsPtrToMember = s instanceof ICPPPointerToMemberType;
final boolean tIsPtrToMember = t instanceof ICPPPointerToMemberType;
if (sIsPtrToMember != tIsPtrToMember) {
return false;
} else if (sIsPtrToMember) {
final IType sMemberOf = ((ICPPPointerToMemberType) s).getMemberOfClass();
final IType tMemberOf = ((ICPPPointerToMemberType) t).getMemberOfClass();
if (sMemberOf == null || tMemberOf == null || !sMemberOf.isSameType(tMemberOf)) {
return false;
}
}
}
}
final IPointerType tPtr = (IPointerType) t;
final IPointerType sPtr = (IPointerType) s;
if (haveMemberPtrConflict(sPtr, tPtr))
return false;
constInEveryCV2k &= (firstPointer || tPtr.isConst());
s= sPtr.getType();
t= tPtr.getType();
@ -912,6 +920,22 @@ public class Conversions {
return s != null && t != null && s.isSameType(t);
}
private static boolean haveMemberPtrConflict(IPointerType s, IPointerType t) {
final boolean sIsPtrToMember = s instanceof ICPPPointerToMemberType;
final boolean tIsPtrToMember = t instanceof ICPPPointerToMemberType;
if (sIsPtrToMember != tIsPtrToMember) {
return true;
}
if (sIsPtrToMember) {
final IType sMemberOf = ((ICPPPointerToMemberType) s).getMemberOfClass();
final IType tMemberOf = ((ICPPPointerToMemberType) t).getMemberOfClass();
if (sMemberOf == null || tMemberOf == null || !sMemberOf.isSameType(tMemberOf)) {
return true;
}
}
return false;
}
/**
* Attempts promotions and returns whether the promotion converted the type.
*
@ -1041,17 +1065,13 @@ public class Conversions {
if (t instanceof IPointerType) {
IPointerType tgtPtr= (IPointerType) t;
if (s instanceof CPPBasicType) {
// 4.10-1 an integral constant expression of integer type that evaluates to 0 can
// be converted to a pointer type
// 4.11-1 same for pointer to member
IASTExpression exp = ((CPPBasicType) s).getCreatedFromExpression();
if (exp != null) {
Long val= Value.create(exp, Value.MAX_RECURSION_DEPTH).numericalValue();
if (val != null && val == 0) {
cost.setRank(Rank.CONVERSION);
return true;
}
// 4.10-1 an integral constant expression of integer type that evaluates to 0 can
// be converted to a pointer type
// 4.11-1 same for pointer to member
if (s instanceof IBasicType) {
if (isNullPointerConstant(s)) {
cost.setRank(Rank.CONVERSION);
return true;
}
return false;
}
@ -1119,6 +1139,19 @@ public class Conversions {
return false;
}
private static boolean isNullPointerConstant(IType s) {
if (s instanceof CPPBasicType) {
IASTExpression exp = ((CPPBasicType) s).getCreatedFromExpression();
if (exp != null) {
Long val= Value.create(exp, Value.MAX_RECURSION_DEPTH).numericalValue();
if (val != null && val == 0) {
return true;
}
}
}
return false;
}
/**
* 4.1, 4.2, 4.3
*/
@ -1136,4 +1169,112 @@ public class Conversions {
}
return uqType;
}
/**
* Composite pointer type computed as described in 5.9-2 except that if the conversion to the
* pointer is not possible, we return null.
*/
public static IType compositePointerType(IType t1, IType t2) {
final boolean isPtr1 = t1 instanceof IPointerType;
if (isPtr1 || isNullPtr(t1)) {
if (isNullPointerConstant(t2)) {
return t1;
}
}
final boolean isPtr2 = t2 instanceof IPointerType;
if (isPtr2 || isNullPtr(t2)) {
if (isNullPointerConstant(t1)) {
return t2;
}
}
if (!isPtr1 || !isPtr2)
return null;
final IPointerType p1= (IPointerType) t1;
final IPointerType p2= (IPointerType) t2;
if (haveMemberPtrConflict(p1, p2))
return null;
final IType target1 = p1.getType();
if (isVoidType(target1)) {
return addQualifiers(p1, p2.isConst(), p2.isVolatile());
}
final IType target2 = p2.getType();
if (isVoidType(target2)) {
return addQualifiers(p2, p1.isConst(), p1.isVolatile());
}
IType t= mergePointers(target1, target2, true);
if (t == null)
return null;
if (t == target1)
return p1;
if (t == target2)
return p2;
return copyPointer(p1, t, false, false);
}
private static IType mergePointers(IType t1, IType t2, boolean allcq) {
t1= getNestedType(t1, TDEF | REF);
t2= getNestedType(t2, TDEF | REF);
if (t1 instanceof IPointerType && t2 instanceof IPointerType) {
final IPointerType p1 = (IPointerType) t1;
final IPointerType p2 = (IPointerType) t2;
final CVQualifier cv1= getCVQualifier(t1);
final CVQualifier cv2= getCVQualifier(t2);
if (haveMemberPtrConflict(p1, p2))
return null;
if (!allcq && cv1 != cv2)
return null;
final IType p1target = p1.getType();
IType merged= mergePointers(p1target, p2.getType(), allcq && (cv1.isConst() || cv2.isConst()));
if (merged == null)
return null;
if (p1target == merged && cv1.isAtLeastAsQualifiedAs(cv2))
return p1;
if (p2.getType() == merged && cv2.isAtLeastAsQualifiedAs(cv1))
return p2;
return copyPointer(p1, merged, cv1.isConst() || cv2.isConst(), cv1.isVolatile() || cv2.isVolatile());
}
final IType uq1= getNestedType(t1, TDEF|REF|CVTYPE);
final IType uq2= getNestedType(t2, TDEF|REF|CVTYPE);
if (uq1 == null || ! uq1.isSameType(uq2))
return null;
if (uq1 == t1 && uq2 == t2)
return t1;
CVQualifier cv1= getCVQualifier(t1);
CVQualifier cv2= getCVQualifier(t2);
if (cv1 == cv2)
return t1;
if (!allcq)
return null;
if (cv1.isAtLeastAsQualifiedAs(cv2))
return t1;
if (cv2.isAtLeastAsQualifiedAs(cv1))
return t2;
// One type is const the other is volatile.
return new CPPQualifierType(uq1, true, true);
}
public static IType copyPointer(final IPointerType p1, IType target, final boolean isConst,
final boolean isVolatile) {
if (p1 instanceof ICPPPointerToMemberType) {
ICPPPointerToMemberType ptm= (ICPPPointerToMemberType) p1;
return new CPPPointerToMemberType(target, ptm.getMemberOfClass(), isConst, isVolatile);
}
return new CPPPointerType(target, isConst, isVolatile);
}
private static boolean isNullPtr(IType t1) {
// mstodo null-ptr type
return false;
}
}

View file

@ -29,11 +29,11 @@ import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPBasicType;
*
* See [over.best.ics] 13.3.3.1.
*/
class Cost {
public class Cost {
public enum DeferredUDC {
NONE, COPY_INIT_OF_CLASS, INIT_BY_CONVERSION, LIST_INIT_OF_CLASS, DIRECT_LIST_INIT_OF_CLASS
}
enum Rank {
public enum Rank {
IDENTITY, PROMOTION, CONVERSION, CONVERSION_PTR_BOOL,
USER_DEFINED_CONVERSION, ELLIPSIS_CONVERSION, NO_MATCH
}

View file

@ -253,12 +253,14 @@ public class SemanticUtil {
t= ((ITypedef) type).getType();
} else if (type instanceof IQualifierType) {
final IQualifierType qt = (IQualifierType) type;
final IType qttgt = qt.getType();
if (allcvq || cvtype) {
t= qt.getType();
t= qttgt;
} else if (tdef) {
t= getNestedType(qt.getType(), options);
t= addQualifiers(t, qt.isConst(), qt.isVolatile());
return t;
t= getNestedType(qttgt, options);
if (t == qttgt)
return qt;
return addQualifiers(t, qt.isConst(), qt.isVolatile());
}
} else if (type instanceof IArrayType) {
final IArrayType atype= (IArrayType) type;