diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2CPPTests.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2CPPTests.java index cdae09cd34f..a5b80a63f97 100644 --- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2CPPTests.java +++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2CPPTests.java @@ -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 Moo; // bool getFile(Moo & 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); // } } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTConditionalExpression.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTConditionalExpression.java index 625bd78928a..3c293e8505b 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTConditionalExpression.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTConditionalExpression.java @@ -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; + } } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/GNUCPPSourceParser.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/GNUCPPSourceParser.java index bbb18d56e8f..178beed0936 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/GNUCPPSourceParser.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/GNUCPPSourceParser.java @@ -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; diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/OverloadableOperator.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/OverloadableOperator.java index 21e91cad214..f55bca64d1f 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/OverloadableOperator.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/OverloadableOperator.java @@ -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; diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/BuiltinOperators.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/BuiltinOperators.java index eb9584c34b8..bd7e20c2c76 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/BuiltinOperators.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/BuiltinOperators.java @@ -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); } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPSemantics.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPSemantics.java index 1a76bac985f..25192d765c3 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPSemantics.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPSemantics.java @@ -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; diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/Conversions.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/Conversions.java index 9746aee7388..77c21f12f98 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/Conversions.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/Conversions.java @@ -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; + } } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/Cost.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/Cost.java index 05d0f4fb91b..639bf3d3f51 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/Cost.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/Cost.java @@ -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 } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/SemanticUtil.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/SemanticUtil.java index 6f8dc782b40..ccb899a822b 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/SemanticUtil.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/SemanticUtil.java @@ -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;