From a0add2323096e35c54a72810251693469ce707a0 Mon Sep 17 00:00:00 2001 From: Markus Schorn Date: Wed, 6 Oct 2010 13:24:38 +0000 Subject: [PATCH] Bug 326900: Update for template argument deduction. --- .../parser/tests/ast2/AST2CPPSpecTest.java | 89 ++++--- .../core/parser/tests/ast2/AST2CPPTests.java | 49 ++++ .../tests/ast2/ASTCPPSpecDefectTests.java | 12 +- .../eclipse/cdt/core/dom/ast/ASTTypeUtil.java | 2 + .../cdt/internal/core/dom/parser/Value.java | 8 +- .../core/dom/parser/cpp/CPPBasicType.java | 1 + .../parser/cpp/CPPTemplateParameterMap.java | 4 + .../parser/cpp/semantics/CPPSemantics.java | 4 +- .../parser/cpp/semantics/CPPTemplates.java | 244 +++++++----------- .../dom/parser/cpp/semantics/CPPVisitor.java | 2 +- .../dom/parser/cpp/semantics/CVQualifier.java | 4 + .../dom/parser/cpp/semantics/Conversions.java | 28 +- .../core/dom/parser/cpp/semantics/Cost.java | 8 +- .../parser/cpp/semantics/FunctionCost.java | 2 +- .../parser/cpp/semantics/SemanticUtil.java | 47 ++++ .../semantics/TemplateArgumentDeduction.java | 221 +++++++++++----- .../dom/parser/cpp/semantics/UniqueType.java | 35 +++ 17 files changed, 493 insertions(+), 267 deletions(-) create mode 100644 core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/UniqueType.java diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2CPPSpecTest.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2CPPSpecTest.java index 5bffdd16b37..28397e2ce21 100644 --- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2CPPSpecTest.java +++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2CPPSpecTest.java @@ -19,6 +19,7 @@ import org.eclipse.cdt.core.dom.ast.IASTDeclaration; import org.eclipse.cdt.core.dom.ast.IASTExpression; import org.eclipse.cdt.core.dom.ast.IASTExpressionList; import org.eclipse.cdt.core.dom.ast.IASTFunctionDefinition; +import org.eclipse.cdt.core.dom.ast.IASTImplicitName; import org.eclipse.cdt.core.dom.ast.IASTName; import org.eclipse.cdt.core.dom.ast.IASTProblemDeclaration; import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit; @@ -35,6 +36,7 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTemplateId; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTUsingDeclaration; import org.eclipse.cdt.core.dom.ast.cpp.ICPPFunction; import org.eclipse.cdt.core.dom.ast.cpp.ICPPFunctionTemplate; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPSpecialization; import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateInstance; import org.eclipse.cdt.core.parser.ParserLanguage; import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPUnknownBinding; @@ -4246,7 +4248,8 @@ public class AST2CPPSpecTest extends AST2SpecBaseTest { // b.f(); //Calls X::f() // } public void test13_3_3_2s3b() throws Exception { - parse(getAboveComment(), ParserLanguage.CPP, true, 0); + String[] problems= {"g"}; + parse(getAboveComment(), ParserLanguage.CPP, problems); } // struct A { @@ -4670,7 +4673,7 @@ public class AST2CPPSpecTest extends AST2SpecBaseTest { // template friend class frd; // // ... // }; - public void test14_5_3s1() throws Exception { + public void test14_5_4s1() throws Exception { parse(getAboveComment(), ParserLanguage.CPP, true, 0); } @@ -4689,7 +4692,7 @@ public class AST2CPPSpecTest extends AST2SpecBaseTest { // }; // } // } - public void test14_5_3s2() throws Exception { + public void test14_5_4s2() throws Exception { parse(getAboveComment(), ParserLanguage.CPP, false, 0); } @@ -4697,7 +4700,7 @@ public class AST2CPPSpecTest extends AST2SpecBaseTest { // template friend class B; // OK // template friend void f(T){ } // OK // }; - public void test14_5_3s3() throws Exception { + public void test14_5_4s3() throws Exception { parse(getAboveComment(), ParserLanguage.CPP, true, 0); } @@ -4707,7 +4710,7 @@ public class AST2CPPSpecTest extends AST2SpecBaseTest { // }; // template struct A { X::Y ab; }; // OK // template struct A { X::Y ab; }; // OK - public void test14_5_3s4() throws Exception { + public void test14_5_4s4() throws Exception { parse(getAboveComment(), ParserLanguage.CPP, true, 0); } @@ -4719,7 +4722,7 @@ public class AST2CPPSpecTest extends AST2SpecBaseTest { // template friend struct A::B; // template friend void A::f(); // }; - public void test14_5_3s6() throws Exception { + public void test14_5_4s6() throws Exception { parse(getAboveComment(), ParserLanguage.CPP, true, 0); } @@ -4731,7 +4734,7 @@ public class AST2CPPSpecTest extends AST2SpecBaseTest { // A::B abcip; // uses #2 // A::B absip; // uses #3 // A::B abci; // uses #1 - public void test14_5_4_3s2() throws Exception { + public void test14_5_5_3s2() throws Exception { parse(getAboveComment(), ParserLanguage.CPP, true, 0); } @@ -4740,13 +4743,13 @@ public class AST2CPPSpecTest extends AST2SpecBaseTest { // template class A { }; // #3 // template class A { }; // #4 // template class A { }; // #5 - public void test14_5_4s4() throws Exception { + public void test14_5_5s4() throws Exception { parse(getAboveComment(), ParserLanguage.CPP, true, 0); } // template struct B {}; // template struct B {}; // OK - public void test14_5_4s9b() throws Exception { + public void test14_5_5s9b() throws Exception { parse(getAboveComment(), ParserLanguage.CPP, true, 0); } @@ -4759,7 +4762,7 @@ public class AST2CPPSpecTest extends AST2SpecBaseTest { // A a2; // uses #2, T is int, I is 1 // A a3; // uses #4, T is char // A a4; // uses #5, T1 is int, T2 is char, I is 1 - public void test14_5_4_1s2a() throws Exception { + public void test14_5_5_1s2a() throws Exception { parse(getAboveComment(), ParserLanguage.CPP, true, 0); } @@ -4769,7 +4772,7 @@ public class AST2CPPSpecTest extends AST2SpecBaseTest { // template class A { }; // #4 // template class A { }; // #5 // A a5; // ambiguous: matches #3 and #5 : expect problem - public void test14_5_4_1s2b() throws Exception { + public void test14_5_5_1s2b() throws Exception { parse(getAboveComment(), ParserLanguage.CPP, true, 1); } @@ -4778,7 +4781,7 @@ public class AST2CPPSpecTest extends AST2SpecBaseTest { // template class X { }; // #2 // template void f(X); // #A // template void f(X); // #B - public void test14_5_4_2s2() throws Exception { + public void test14_5_5_2s2() throws Exception { parse(getAboveComment(), ParserLanguage.CPP, true, 0); } @@ -4809,13 +4812,13 @@ public class AST2CPPSpecTest extends AST2SpecBaseTest { // a2.f(); //illformed, no definition of f for A // // the primary template is not used here // } - public void test14_5_4_3s1() throws Exception { + public void test14_5_5_3s1() throws Exception { parse(getAboveComment(), ParserLanguage.CPP, false, 0); } // template class Array { }; // template void sort(Array&); - public void test14_5_5s1() throws Exception { + public void test14_5_6s1() throws Exception { parse(getAboveComment(), ParserLanguage.CPP, true, 0); } @@ -4826,7 +4829,7 @@ public class AST2CPPSpecTest extends AST2SpecBaseTest { // f(p); // call // // f(int*) // } - public void test14_5_5_1s1a() throws Exception { + public void test14_5_6_1s1a() throws Exception { parse(getAboveComment(), ParserLanguage.CPP, true, 0); } // // file2.c @@ -4836,7 +4839,7 @@ public class AST2CPPSpecTest extends AST2SpecBaseTest { // f(p); // call // // f(int*) // } - public void test14_5_5_1s1b() throws Exception { + public void test14_5_6_1s1b() throws Exception { parse(getAboveComment(), ParserLanguage.CPP, true, 0); } @@ -4846,7 +4849,7 @@ public class AST2CPPSpecTest extends AST2SpecBaseTest { // template void f/*2*/(A, A); // // Guaranteed to be different // template void f/*3*/(A, A); - public void test14_5_5_1s8a() throws Exception { + public void test14_5_6_1s8a() throws Exception { final String content= getAboveComment(); IASTTranslationUnit tu= parse(content, ParserLanguage.CPP, true, 0); BindingAssertionHelper bh= new BindingAssertionHelper(content, true); @@ -4860,11 +4863,33 @@ public class AST2CPPSpecTest extends AST2SpecBaseTest { // // Illformed, no diagnostic required // template void f(A, A); // template void f(A, A); - public void test14_5_5_1s8b() throws Exception { + public void test14_5_6_1s8b() throws Exception { //test is only for syntax, semantics are not checked here. parse(getAboveComment(), ParserLanguage.CPP, false, 0); } + // struct A { }; + // template struct B { + // template int operator*(R&); // #1 + // }; + // template int operator*(T&, R&); // #2 + // // The declaration of B::operator* is transformed into the equivalent of + // // template int operator*(B&, R&); // #1a + // int main() { + // A a; + // B b; + // b * a; // calls #1a + // } + public void test14_5_6_2s3() throws Exception { + String code= getAboveComment(); + BindingAssertionHelper bh= new BindingAssertionHelper(code, true); + IBinding op1= bh.assertNonProblem("operator*(R&)", -4); + IASTImplicitName name= bh.assertImplicitName("* a", 1, ICPPFunction.class); + ICPPTemplateInstance inst= (ICPPTemplateInstance) name.resolveBinding(); + ICPPSpecialization templateSpecialization = (ICPPSpecialization) inst.getTemplateDefinition(); + assertSame(op1, templateSpecialization.getSpecializedBinding()); + } + // template struct A { A(); }; // template void f(T); // template void f(T*); @@ -4883,7 +4908,7 @@ public class AST2CPPSpecTest extends AST2SpecBaseTest { // const A z2; // h(z2); // h(const T&) is called because h(A&) is not callable // } - public void test14_5_5_2s5() throws Exception { + public void test14_5_6_2s5() throws Exception { parse(getAboveComment(), ParserLanguage.CPP, false, 0); } @@ -4896,7 +4921,7 @@ public class AST2CPPSpecTest extends AST2SpecBaseTest { // f(ip); //calls #2 // g(ip); //calls #4 // } - public void test14_5_5_2s6() throws Exception { + public void test14_5_6_2s6() throws Exception { parse(getAboveComment(), ParserLanguage.CPP, true, 0); } @@ -5657,7 +5682,7 @@ public class AST2CPPSpecTest extends AST2SpecBaseTest { // template int f(T[5]); // int I = f(0); - // int j = f(0); // invalid array + // int j = f(0); // invalid array // also no error with gcc public void _test14_8_2s8b() throws Exception { final String content= getAboveComment(); BindingAssertionHelper bh= new BindingAssertionHelper(content, true); @@ -5829,7 +5854,7 @@ public class AST2CPPSpecTest extends AST2SpecBaseTest { // char g(char); // template T g(T); // int i = f(1, g); // calls f(int, int (*)(int)) - public void _test14_8_2_1s9() throws Exception { + public void test14_8_2_1s9() throws Exception { final String code= getAboveComment(); BindingAssertionHelper bh= new BindingAssertionHelper(code, true); ICPPTemplateInstance inst; @@ -5962,13 +5987,13 @@ public class AST2CPPSpecTest extends AST2SpecBaseTest { // f(i); // calls f(int&), i.e., #1 // f(0); // calls f(int&&), i.e., #2 // } - public void _test14_8_2_5s10() throws Exception { + public void test14_8_2_5s10() throws Exception { final String code= getAboveComment(); BindingAssertionHelper bh= new BindingAssertionHelper(code, true); ICPPTemplateInstance inst; inst= bh.assertNonProblem("f(i)", 1); assertEquals("", ASTTypeUtil.getArgumentListString(inst.getTemplateArguments(), true)); - inst= bh.assertNonProblem("f(i)", 1); + inst= bh.assertNonProblem("f(0)", 1); assertEquals("", ASTTypeUtil.getArgumentListString(inst.getTemplateArguments(), true)); } @@ -6021,7 +6046,7 @@ public class AST2CPPSpecTest extends AST2SpecBaseTest { // g<0>(a1); // OK // f(a1, a2); // OK // } - public void _test14_8_2_5s16a() throws Exception { + public void test14_8_2_5s16a() throws Exception { final String code= getAboveComment(); BindingAssertionHelper bh= new BindingAssertionHelper(code, true); ICPPTemplateInstance inst; @@ -6069,7 +6094,7 @@ public class AST2CPPSpecTest extends AST2SpecBaseTest { // B<1> b; // g(b); // OK: cv-qualifiers are ignored on template parameter types // } - public void _test14_8_2_5s17() throws Exception { + public void test14_8_2_5s17() throws Exception { final String code= getAboveComment(); BindingAssertionHelper bh= new BindingAssertionHelper(code, true); ICPPTemplateInstance inst; @@ -6684,7 +6709,7 @@ public class AST2CPPSpecTest extends AST2SpecBaseTest { } // template class A { }; // error - public void test14_5_4s5() throws Exception { + public void test14_5_5s5() throws Exception { parse(getAboveComment(), ParserLanguage.CPP, false, 0); } @@ -6697,7 +6722,7 @@ public class AST2CPPSpecTest extends AST2SpecBaseTest { // template template // struct A::C::B { }; // A::C::B absip; // uses partial specialization - public void test14_5_4s6() throws Exception { + public void test14_5_5s6() throws Exception { parse(getAboveComment(), ParserLanguage.CPP, true, 0); } @@ -6710,14 +6735,14 @@ public class AST2CPPSpecTest extends AST2SpecBaseTest { // } // A a; // uses the partial specialization, which is found through // // the using declaration which refers to the primary template - public void test14_5_4s7() throws Exception { + public void test14_5_5s7() throws Exception { parse(getAboveComment(), ParserLanguage.CPP, true, 0); } // template void f(); // template void f(); // OK: overloads the first template // // distinguishable with an explicit template argument list - public void test14_5_5_1s4() throws Exception { + public void test14_5_6_1s4() throws Exception { parse(getAboveComment(), ParserLanguage.CPP, true, 0); } @@ -6725,7 +6750,7 @@ public class AST2CPPSpecTest extends AST2SpecBaseTest { // template A f/*1*/(A, A); // #1 // template A f/*2*/(A, A); // same as #1 // template A f/*3*/(A, A); // different from #1 - public void test14_5_5_1s5() throws Exception { + public void test14_5_6_1s5() throws Exception { final String content= getAboveComment(); IASTTranslationUnit tu= parse(content, ParserLanguage.CPP, true, 0); BindingAssertionHelper bh= new BindingAssertionHelper(content, true); @@ -6739,7 +6764,7 @@ public class AST2CPPSpecTest extends AST2SpecBaseTest { // template class A; // template void f/*1*/(A); // #1 // template void f/*2*/(A); // same as #1 - public void test14_5_5_1s6() throws Exception { + public void test14_5_6_1s6() throws Exception { final String content= getAboveComment(); IASTTranslationUnit tu= parse(content, ParserLanguage.CPP, true, 0); BindingAssertionHelper bh= new BindingAssertionHelper(content, true); 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 b5aeac6af1f..e70c4801fc8 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 @@ -4896,6 +4896,55 @@ public class AST2CPPTests extends AST2BaseTest { assertSame( col.getName(2).resolveBinding(), col.getName(5).resolveBinding() ); } + // void f(const int&); + // void f(int&); + // void g(const int&); + // void g(int); + // void h(const int * const&); + // void h(int *); + // void i(int * const &); + // void i(const int *); + // void test() { + // const int ca= 1; int a; + // f(ca); // f(const int&) + // f(a); // f(int &) + // g(ca); // ambiguous + // g(a); // ambiguous + // h(&ca); // h(const int * const&) + // h(&a); // void h(int *) + // i(&ca); // i(const int *) + // i(&a); // i(int * const &) + // } + public void testRankingQualificationConversions_c() throws Exception { + String code= getAboveComment(); + BindingAssertionHelper bh= new BindingAssertionHelper(code, true); + + ICPPFunction f1= bh.assertNonProblem("f(const int&)", 1); + ICPPFunction f2= bh.assertNonProblem("f(int&)", 1); + ICPPFunction g1= bh.assertNonProblem("g(const int&)", 1); + ICPPFunction g2= bh.assertNonProblem("g(int)", 1); + ICPPFunction h1= bh.assertNonProblem("h(const int * const&)", 1); + ICPPFunction h2= bh.assertNonProblem("h(int *)", 1); + ICPPFunction i1= bh.assertNonProblem("i(int * const &)", 1); + ICPPFunction i2= bh.assertNonProblem("i(const int *)", 1); + + ICPPFunction ref; + ref= bh.assertNonProblem("f(ca)", 1); + assertSame(f1, ref); + ref= bh.assertNonProblem("f(a)", 1); + assertSame(f2, ref); + bh.assertProblem("g(ca)", 1); + bh.assertProblem("g(a)", 1); + ref= bh.assertNonProblem("h(&ca)", 1); + assertSame(h1, ref); + ref= bh.assertNonProblem("h(&a)", 1); + assertSame(h2, ref); + ref= bh.assertNonProblem("i(&ca)", 1); + assertSame(i2, ref); + ref= bh.assertNonProblem("i(&a)", 1); + assertSame(i1, ref); + } + // namespace n { // namespace m { // class A; diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/ASTCPPSpecDefectTests.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/ASTCPPSpecDefectTests.java index 4ce37374d46..3a67049702c 100644 --- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/ASTCPPSpecDefectTests.java +++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/ASTCPPSpecDefectTests.java @@ -64,7 +64,7 @@ public class ASTCPPSpecDefectTests extends AST2BaseTest { // void test() { // fp(f0); // } - public void testADLForOverloadSet_324842() throws Exception { + public void test33_ADLForOverloadSet_324842() throws Exception { parseAndCheckBindings(); } @@ -73,7 +73,15 @@ public class ASTCPPSpecDefectTests extends AST2BaseTest { // struct A { // friend A operator + <>(A&); // }; - public void testTemplateArgForOperator() throws Exception { + public void test38_templateArgForOperator() throws Exception { + parseAndCheckBindings(); + } + + // template class S; // #1 + // template class S {}; // #2 + // template class S {};; // #3 + // S s; // both #2 and #3 match; #3 is more specialized + public void test692_partialOrdering() throws Exception { parseAndCheckBindings(); } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/ASTTypeUtil.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/ASTTypeUtil.java index 74185944898..8e194b2a9b1 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/ASTTypeUtil.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/ASTTypeUtil.java @@ -416,6 +416,8 @@ public class ASTTypeUtil { needSpace= appendCVQ(result, needSpace, qt.isConst(), qt.isVolatile()); } else if (type instanceof ITypedef) { result.append(((ITypedef) type).getNameCharArray()); + } else if (type != null) { + result.append('@').append(type.hashCode()); } return result.toString(); diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/Value.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/Value.java index 298af6d1693..db792131ca2 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/Value.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/Value.java @@ -446,7 +446,7 @@ public class Value implements IValue { unknownSigs.put(sig, idx); unknowns.add(unknown); } - return REFERENCE_CHAR + idx.toString(); + return "" + REFERENCE_CHAR + idx.toString(); //$NON-NLS-1$ } private static Object evaluateValue(IValue cv, Map unknownSigs, List unknowns) throws UnknownValueException { @@ -536,7 +536,7 @@ public class Value implements IValue { case IASTUnaryExpression.op_minus: case IASTUnaryExpression.op_tilde: case IASTUnaryExpression.op_not: - return UNARY_OP_CHAR + unaryOp + SEPARATOR + value.toString(); + return "" + UNARY_OP_CHAR + unaryOp + SEPARATOR + value.toString(); //$NON-NLS-1$ } throw UNKNOWN_EX; } @@ -634,7 +634,7 @@ public class Value implements IValue { throw UNKNOWN_EX; } - return BINARY_OP_CHAR + op + SEPARATOR + o1.toString() + SEPARATOR + o2.toString(); + return "" + BINARY_OP_CHAR + op + SEPARATOR + o1.toString() + SEPARATOR + o2.toString(); //$NON-NLS-1$ } public static IValue reevaluate(IValue val, int packOffset, IBinding[] resolvedUnknowns, ICPPTemplateParameterMap map, int maxdepth) { @@ -699,7 +699,7 @@ public class Value implements IValue { } return po; } - return CONDITIONAL_CHAR + SEPARATOR + cond.toString() + SEPARATOR + po.toString() + SEPARATOR + neg.toString(); + return "" + CONDITIONAL_CHAR + SEPARATOR + cond.toString() + SEPARATOR + po.toString() + SEPARATOR + neg.toString(); //$NON-NLS-1$ case REFERENCE_CHAR: int num= parseNonNegative(buf, idx+1); final IBinding[] resolvedUnknowns= reeval.fResolvedUnknown; diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPBasicType.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPBasicType.java index 47e6dc79889..1d270f85985 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPBasicType.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPBasicType.java @@ -27,6 +27,7 @@ import org.eclipse.core.runtime.CoreException; * Integral c++ type. */ public class CPPBasicType implements ICPPBasicType, ISerializableType { + // mstodo replace with problem type public static int UNIQUE_TYPE_QUALIFIER= -1; private final Kind fKind; private final int fModifiers; diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPTemplateParameterMap.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPTemplateParameterMap.java index 5426aa1dc81..d1ce349769a 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPTemplateParameterMap.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPTemplateParameterMap.java @@ -31,6 +31,10 @@ public class CPPTemplateParameterMap implements ICPPTemplateParameterMap { fMap= new ObjectMap(initialSize); } + public CPPTemplateParameterMap(CPPTemplateParameterMap other) { + fMap= (ObjectMap) other.fMap.clone(); + } + /** * Returns whether the map contains the given parameter */ 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 113bef2ff14..89060122494 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 @@ -2294,7 +2294,7 @@ public class CPPSemantics { return resolveFunctionDeclaration(data, fns); // Reduce our set of candidate functions to only those who have the right number of parameters - final IType[] argTypes = data.getFunctionArgumentTypes(); + final IType[] argTypes = data.getFunctionArgumentTypes(); ICPPFunction[] tmp= selectByArgumentCount(data, fns); tmp= CPPTemplates.instantiateForFunctionCall(data.astName, tmp, Arrays.asList(argTypes), @@ -2820,7 +2820,7 @@ public class CPPSemantics { if (inst != null) { int cmp= -1; if (result != null) { - cmp= CPPTemplates.orderTemplateFunctions(resultTemplate, template); + cmp= CPPTemplates.orderFunctionTemplates(resultTemplate, template); if (cmp == 0) cmp= compareByRelevance(tu, resultTemplate, template); } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPTemplates.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPTemplates.java index ab1bd0f882f..95716c576ca 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPTemplates.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPTemplates.java @@ -14,14 +14,11 @@ package org.eclipse.cdt.internal.core.dom.parser.cpp.semantics; import static org.eclipse.cdt.core.dom.ast.IASTExpression.ValueCategory.LVALUE; +import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.addQualifiers; import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; import java.util.Collections; -import java.util.HashSet; import java.util.List; -import java.util.Set; import org.eclipse.cdt.core.dom.IName; import org.eclipse.cdt.core.dom.ast.ASTTypeUtil; @@ -41,8 +38,6 @@ import org.eclipse.cdt.core.dom.ast.IASTName; import org.eclipse.cdt.core.dom.ast.IASTNode; import org.eclipse.cdt.core.dom.ast.IASTSimpleDeclaration; import org.eclipse.cdt.core.dom.ast.IArrayType; -import org.eclipse.cdt.core.dom.ast.IBasicType; -import org.eclipse.cdt.core.dom.ast.IBasicType.Kind; import org.eclipse.cdt.core.dom.ast.IBinding; import org.eclipse.cdt.core.dom.ast.IEnumeration; import org.eclipse.cdt.core.dom.ast.IEnumerator; @@ -104,7 +99,6 @@ import org.eclipse.cdt.internal.core.dom.parser.ProblemBinding; 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.CPPArrayType; -import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPBasicType; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPClassInstance; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPClassSpecialization; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPClassTemplatePartialSpecialization; @@ -125,6 +119,7 @@ import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPMethodTemplateSpecializat import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPParameterPackType; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPPointerToMemberType; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPPointerType; +import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPReferenceType; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPTemplateArgument; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPTemplateDefinition; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPTemplateNonTypeParameter; @@ -157,7 +152,7 @@ public class CPPTemplates { private static final int PACK_SIZE_FAIL = -2; private static final int PACK_SIZE_NOT_FOUND = Integer.MAX_VALUE; private static final ICPPFunction[] NO_FUNCTIONS = {}; - + /** * Instantiates a class template with the given arguments. May return null. */ @@ -1111,10 +1106,9 @@ public class CPPTemplates { ICPPPointerToMemberType ptm = (ICPPPointerToMemberType) typeContainer; IType memberOfClass = ptm.getMemberOfClass(); IType newMemberOfClass = instantiateType(memberOfClass, tpMap, packOffset, within); - if (!(newMemberOfClass instanceof ICPPClassType) && - !(newMemberOfClass instanceof IBasicType && ((IBasicType) newMemberOfClass).getModifiers() == CPPBasicType.UNIQUE_TYPE_QUALIFIER) && - !(newMemberOfClass instanceof ICPPUnknownBinding)) { - newMemberOfClass= memberOfClass; + if (!(newMemberOfClass instanceof ICPPClassType || newMemberOfClass instanceof UniqueType + || newMemberOfClass instanceof ICPPUnknownBinding)) { + newMemberOfClass = memberOfClass; } if (newNestedType != nestedType || newMemberOfClass != memberOfClass) { return new CPPPointerToMemberType(newNestedType, newMemberOfClass, @@ -1580,16 +1574,13 @@ public class CPPTemplates { return fns; final List result= new ArrayList(fns.length); - final List> crossProduct= expandOverloadedSets(fnArgs); for (ICPPFunction fn : fns) { if (fn != null) { if (fn instanceof ICPPFunctionTemplate) { ICPPFunctionTemplate fnTmpl= (ICPPFunctionTemplate) fn; - for (List args : crossProduct) { - ICPPFunction inst = instantiateForFunctionCall(fnTmpl, tmplArgs, args, argCats, withImpliedObjectArg); - if (inst != null) - result.add(inst); - } + ICPPFunction inst = instantiateForFunctionCall(fnTmpl, tmplArgs, fnArgs, argCats, withImpliedObjectArg); + if (inst != null) + result.add(inst); } else if (!requireTemplate || fn instanceof ICPPUnknownBinding) { result.add(fn); } @@ -1598,47 +1589,6 @@ public class CPPTemplates { return result.toArray(new ICPPFunction[result.size()]); } - private static List> expandOverloadedSets(List fnArgs) { - List> result= Collections.singletonList(fnArgs); - int i= 0; - for (IType arg : fnArgs) { - if (arg instanceof FunctionSetType) { - Collection targetTypes= getFunctionTypes((FunctionSetType) arg); - if (targetTypes.isEmpty()) - return Collections.emptyList(); - - List> expanded= new ArrayList>(targetTypes.size() * result.size()); - for (IType targetType : targetTypes) { - for (List orig : result) { - ArrayList copy = new ArrayList(orig); - copy.set(i, new CPPPointerType(targetType)); - expanded.add(copy); - } - } - result= expanded; - } - i++; - } - return result; - } - - private static Collection getFunctionTypes(FunctionSetType fst) { - final ICPPFunction[] functionSet = fst.getFunctionSet(); - Set handled= new HashSet(); - Collection result= new ArrayList(functionSet.length); - for (ICPPFunction f : functionSet) { - if (! (f instanceof ICPPFunctionTemplate)) { - try { - ICPPFunctionType t= f.getType(); - if (handled.add(ASTTypeUtil.getType(t, true))) - result.add(t); - } catch (DOMException e) { - } - } - } - return result; - } - private static ICPPFunction instantiateForFunctionCall(ICPPFunctionTemplate template, ICPPTemplateArgument[] tmplArgs, List fnArgs, List argCats, boolean withImpliedObjectArg) { @@ -1732,90 +1682,92 @@ public class CPPTemplates { return null; } - - /** - * Transforms a function template for use in partial ordering, as described in the - * spec 14.5.5.2-3 - * @param template - * @return - * -for each type template parameter, synthesize a unique type and substitute that for each - * occurrence of that parameter in the function parameter list - * -for each non-type template parameter, synthesize a unique value of the appropriate type and - * substitute that for each occurrence of that parameter in the function parameter list - * for each template template parameter, synthesize a unique class template and substitute that - * for each occurrence of that parameter in the function parameter list - * @throws DOMException - */ - static private ICPPTemplateArgument[] createArgsForFunctionTemplateOrdering(ICPPTemplateParameter[] paramList) - throws DOMException{ - int size = paramList.length; - ICPPTemplateArgument[] args = new ICPPTemplateArgument[size]; - for (int i = 0; i < size; i++) { - ICPPTemplateParameter param = paramList[i]; - if (param instanceof ICPPTemplateNonTypeParameter) { - args[i]= new CPPTemplateArgument(Value.unique(), ((ICPPTemplateNonTypeParameter) param).getType()); - } else { - args[i] = new CPPTemplateArgument(new CPPBasicType(Kind.eUnspecified, CPPBasicType.UNIQUE_TYPE_QUALIFIER)); - } - } - return args; - } - - static int orderTemplateFunctions(ICPPFunctionTemplate f1, ICPPFunctionTemplate f2) + // 14.5.6.2 Partial ordering of function templates + static int orderFunctionTemplates(ICPPFunctionTemplate f1, ICPPFunctionTemplate f2) throws DOMException { - // 14.5.5.2 - // A template is more specialized than another if and only if it is at least as specialized as the - // other template and that template is not at least as specialized as the first. - boolean f1IsAtLeastAsSpecializedAsF2 = isAtLeastAsSpecializedAs(f1, f2); - boolean f2IsAtLeastAsSpecializedAsF1 = isAtLeastAsSpecializedAs(f2, f1); - - if (f1IsAtLeastAsSpecializedAsF2 == f2IsAtLeastAsSpecializedAsF1) + int s1 = compareSpecialization(f1, f2); + int s2 = compareSpecialization(f2, f1); + + if (s1 == s2) return 0; - - if (f1IsAtLeastAsSpecializedAsF2) - return 1; - - return -1; + if (s1 < 0 || s2 > 0) + return -1; + assert s2 < 0 || s1 > 0; + return 1; } - private static boolean isAtLeastAsSpecializedAs(ICPPFunctionTemplate f1, ICPPFunctionTemplate f2) throws DOMException { - // mstodo use function-type, parameter-types or return type. - // mstodo perform transformations (references, cv-qualifiers) - // mstodo if equal, use differences in cv-qualifiers - // mstodo special rule for parameter packs. - // 14.5.5.2 - // Using the transformed parameter list, perform argument deduction against the other - // function template - // The transformed template is at least as specialized as the other if and only if the deduction - // succeeds and the deduced parameter types are an exact match. + private static ICPPFunction transferFunctionTemplate(ICPPFunctionTemplate f) throws DOMException { + final ICPPTemplateParameter[] tpars = f.getTemplateParameters(); + final int argLen = tpars.length; - // Check for parameter packs - - final ICPPTemplateParameter[] tmplParams1 = f1.getTemplateParameters(); - ICPPTemplateArgument[] transferArgs = createArgsForFunctionTemplateOrdering(tmplParams1); - - final int length = transferArgs.length; - CPPTemplateParameterMap map = new CPPTemplateParameterMap(length); - for (int i = 0; i < length; i++) { - map.put(tmplParams1[i], transferArgs[i]); - } - IBinding transferredTemplate = instantiateFunctionTemplate(f1, transferArgs, map); - if (!(transferredTemplate instanceof ICPPFunction)) - return false; - - map= new CPPTemplateParameterMap(2); - final IType[] transferredParameterTypes = ((ICPPFunction) transferredTemplate).getType().getParameterTypes(); - if (!TemplateArgumentDeduction.deduceFromFunctionArgs(f2, Arrays.asList(transferredParameterTypes), null, map, true)) - return false; - - final int last = tmplParams1.length -1; - if (last >= 0 && tmplParams1[last].isParameterPack()) { - final ICPPTemplateParameter[] tmplParams2 = f2.getTemplateParameters(); - if (last < tmplParams2.length && !tmplParams2[last].isParameterPack()) { - return false; + // Create arguments and map + ICPPTemplateArgument[] args = new ICPPTemplateArgument[argLen]; + CPPTemplateParameterMap map = new CPPTemplateParameterMap(argLen); + for (int i = 0; i < argLen; i++) { + final ICPPTemplateParameter tpar = tpars[i]; + final CPPTemplateArgument arg = uniqueArg(tpar); + args[i]= arg; + if (tpar.isParameterPack()) { + map.put(tpar, new ICPPTemplateArgument[] {arg}); + } else { + map.put(tpar, arg); } } - return true; + + IBinding result = instantiateFunctionTemplate(f, args, map); + if (result instanceof ICPPFunction) + return (ICPPFunction) result; + + return null; + } + + private static CPPTemplateArgument uniqueArg(final ICPPTemplateParameter tpar) throws DOMException { + final CPPTemplateArgument arg; + if (tpar instanceof ICPPTemplateNonTypeParameter) { + arg = new CPPTemplateArgument(Value.unique(), ((ICPPTemplateNonTypeParameter) tpar).getType()); + } else { + arg = new CPPTemplateArgument(new UniqueType(tpar.isParameterPack())); + } + return arg; + } + + private static int compareSpecialization(ICPPFunctionTemplate f1, ICPPFunctionTemplate f2) throws DOMException { + ICPPFunction transF1 = transferFunctionTemplate(f1); + if (transF1 == null) + return -1; + + // mstodo use function-type, parameter-types or return type. + IType[] pars= f2.getType().getParameterTypes(); + IType[] args = transF1.getType().getParameterTypes(); + boolean nonStaticMember1= isNonStaticMember(f1); + boolean nonStaticMember2= isNonStaticMember(f2); + if (nonStaticMember1 != nonStaticMember2) { + if (nonStaticMember1) { + args= addImplicitObjectType(args, (ICPPMethod) f1); + } else { + pars= addImplicitObjectType(pars, (ICPPMethod) f2); + } + } + return TemplateArgumentDeduction.deduceForPartialOrdering(f2.getTemplateParameters(), pars, args); + } + + private static boolean isNonStaticMember(ICPPFunctionTemplate f) { + return (f instanceof ICPPMethod) && !((ICPPMethod) f).isStatic(); + } + + private static IType[] addImplicitObjectType(IType[] types, ICPPMethod f1) { + ICPPClassType ct = f1.getClassOwner(); + if (ct != null) { + try { + ICPPFunctionType ft = f1.getType(); + IType[] result= new IType[types.length+1]; + result[0]= new CPPReferenceType(addQualifiers(ct, ft.isConst(), ft.isVolatile()), false); + System.arraycopy(types, 0, result, 1, types.length); + return result; + } catch (DOMException e) { + } + } + return types; } private static ICPPClassTemplatePartialSpecialization findPartialSpecialization(ICPPClassTemplate ct, @@ -1918,21 +1870,25 @@ public class CPPTemplates { final ICPPTemplateArgument[] targs2 = f2.getTemplateArguments(); if (targs1.length != targs2.length) return false; - - // transfer arguments of specialization 1 - final ICPPTemplateArgument[] helperArgs = createArgsForFunctionTemplateOrdering(tpars1); - final CPPTemplateParameterMap transferMap= new CPPTemplateParameterMap(5); - for (int i = 0; i < tpars1.length; i++) { - transferMap.put(tpars1[i], helperArgs[i]); + + // Transfer arguments of specialization 1 + final int tpars1Len = tpars1.length; + ICPPTemplateArgument[] args = new ICPPTemplateArgument[tpars1Len]; + final CPPTemplateParameterMap transferMap= new CPPTemplateParameterMap(tpars1Len); + for (int i = 0; i < tpars1Len; i++) { + final ICPPTemplateParameter param = tpars1[i]; + final CPPTemplateArgument arg = uniqueArg(param); + args[i]= arg; + transferMap.put(param, arg); } final ICPPTemplateArgument[] transferredArgs1 = instantiateArguments(targs1, transferMap, -1, null); - // deduce arguments for specialization 2 + // Deduce arguments for specialization 2 final CPPTemplateParameterMap deductionMap= new CPPTemplateParameterMap(2); if (!TemplateArgumentDeduction.fromTemplateArguments(tpars2, targs2, transferredArgs1, deductionMap)) return false; - // compare + // Compare for (int i = 0; i < targs2.length; i++) { ICPPTemplateArgument transferredArg2= instantiateArgument(targs2[i], deductionMap, -1, null); if (!transferredArg2.isSameValue(transferredArgs1[i])) diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPVisitor.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPVisitor.java index 94c810bb8df..61bc31e8668 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPVisitor.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPVisitor.java @@ -1821,7 +1821,7 @@ public class CPPVisitor extends ASTQueries { ICPPFunctionTemplate template = new AutoTypeResolver(type); CPPTemplateParameterMap paramMap = new CPPTemplateParameterMap(1); TemplateArgumentDeduction.deduceFromFunctionArgs(template, Collections.singletonList(initType), - Collections.singletonList(valueCat), paramMap, false); + Collections.singletonList(valueCat), paramMap); ICPPTemplateArgument argument = paramMap.getArgument(0, 0); if (argument == null) { return null; diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CVQualifier.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CVQualifier.java index 0106034ba6e..0a16bce192b 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CVQualifier.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CVQualifier.java @@ -35,6 +35,10 @@ public enum CVQualifier { return other == _ || this == other || this == cv; } + public boolean isMoreQualifiedThan(CVQualifier other) { + return this != other && (other == _ || this == cv); + } + public CVQualifier remove(CVQualifier arg) { if (this == arg) return _; 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 58fb82b7b13..8fa0fc4f2f5 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 @@ -95,8 +95,8 @@ public class Conversions { final IType cv1T1= getNestedType(target, TDEF | REF); final IType T1= getNestedType(cv1T1, TDEF | REF | ALLCVQ); - ReferenceBinding refBindingType= ReferenceBinding.OTHER; if (target instanceof ICPPReferenceType) { + ReferenceBinding refBindingType= ReferenceBinding.OTHER_REF; // [8.5.3-5] initialization of a reference final boolean isLValueRef= !((ICPPReferenceType) target).isRValueReference(); final IType cv2T2= exprType; @@ -239,8 +239,8 @@ public class Conversions { 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()) { - cost.setReferenceBinding(isLValueRef ? ReferenceBinding.LVALUE_REF : ReferenceBinding.RVALUE_REF_BINDS_RVALUE); + if (cost.converts()) { + cost.setReferenceBinding(refBindingType); } return cost; } @@ -249,11 +249,7 @@ public class Conversions { } // Non-reference binding - Cost cost= nonReferenceConversion(valueCat, exprType, T1, udc, isImpliedObject); - if (cost.converts()) { - cost.setReferenceBinding(refBindingType); - } - return cost; + return nonReferenceConversion(valueCat, exprType, T1, udc, isImpliedObject); } /** @@ -279,6 +275,8 @@ public class Conversions { IType implicitParameterType= CPPSemantics.getImplicitParameterType(op, ft.isConst(), ft.isVolatile()); Cost udcCost= isReferenceCompatible(getNestedType(implicitParameterType, TDEF | REF), cv2T2, true); // expression type to implicit object type if (udcCost != null) { + // Make sure top-level cv-qualifiers are compared + udcCost.setReferenceBinding(ReferenceBinding.LVALUE_REF); FunctionCost udcFuncCost= new FunctionCost(op, udcCost); int cmp= udcFuncCost.compareTo(null, bestUdcCost); if (cmp <= 0) { @@ -729,6 +727,8 @@ public class Conversions { IType implicitType= CPPSemantics.getImplicitParameterType(op, ft.isConst(), ft.isVolatile()); final Cost udcCost = isReferenceCompatible(getNestedType(implicitType, TDEF | REF), source, true); if (udcCost != null) { + // Make sure top-level cv-qualifiers are compared + udcCost.setReferenceBinding(ReferenceBinding.LVALUE_REF); FunctionCost c1= new FunctionCost(op, udcCost); int cmp= c1.compareTo(null, cost1); if (cmp <= 0) { @@ -783,6 +783,8 @@ public class Conversions { IType implicitType= CPPSemantics.getImplicitParameterType(op, ftype.isConst(), ftype.isVolatile()); final Cost udcCost = isReferenceCompatible(getNestedType(implicitType, TDEF | REF), source, true); if (udcCost != null) { + // Make sure top-level cv-qualifiers are compared + udcCost.setReferenceBinding(ReferenceBinding.LVALUE_REF); FunctionCost c1= new FunctionCost(op, udcCost); int cmp= c1.compareTo(null, cost1); if (cmp <= 0) { @@ -868,7 +870,7 @@ public class Conversions { IASTLiteralExpression lit= (IASTLiteralExpression) val; if (lit.getKind() == IASTLiteralExpression.lk_string_literal) { source= new CPPPointerType(srcTarget, false, false); - cost.setQualificationAdjustment(getCVQualifier(targetPtrTgt).isVolatile() ? 2 : 1); + cost.setQualificationAdjustment((getCVQualifier(targetPtrTgt).isVolatile() ? 2 : 1) << 2); } } } @@ -886,11 +888,11 @@ public class Conversions { boolean constInEveryCV2k = true; boolean firstPointer= true; int adjustments= 0; + int shift=0; while (true) { s= getNestedType(s, TDEF | REF); t= getNestedType(t, TDEF | REF); if (s instanceof IPointerType && t instanceof IPointerType) { - adjustments <<= 2; final int cmp= compareQualifications(t, s); // is t more qualified than s? if (cmp < 0 || (cmp > 0 && !constInEveryCV2k)) { return false; @@ -904,19 +906,19 @@ public class Conversions { s= sPtr.getType(); t= tPtr.getType(); firstPointer= false; - adjustments |= cmp; + adjustments |= (cmp << shift); + shift+= 2; } else { break; } } - adjustments <<= 2; int cmp= compareQualifications(t, s); // is t more qualified than s? if (cmp < 0 || (cmp > 0 && !constInEveryCV2k)) { return false; } - adjustments |= cmp; + adjustments |= (cmp << shift); s= getNestedType(s, ALLCVQ | TDEF | REF); t= getNestedType(t, ALLCVQ | TDEF | REF); 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 84c8c2ebc51..6b0a00d4612 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 @@ -38,7 +38,7 @@ public class Cost { USER_DEFINED_CONVERSION, ELLIPSIS_CONVERSION, NO_MATCH } enum ReferenceBinding { - RVALUE_REF_BINDS_RVALUE, LVALUE_REF, OTHER + RVALUE_REF_BINDS_RVALUE, LVALUE_REF, OTHER_REF, NO_REF } public static final Cost NO_CONVERSION = new Cost(null, null, Rank.NO_MATCH) { @@ -99,7 +99,7 @@ public class Cost { source = s; target = t; fRank= rank; - fReferenceBinding= ReferenceBinding.OTHER; + fReferenceBinding= ReferenceBinding.NO_REF; } public final Rank getRank() { @@ -207,7 +207,11 @@ public class Cost { return -1; } + // Top level cv-qualifiers are compared only for reference bindings. int qdiff= fQualificationAdjustments ^ other.fQualificationAdjustments; + if (fReferenceBinding == ReferenceBinding.NO_REF || other.fReferenceBinding == ReferenceBinding.NO_REF) + qdiff &= ~3; + if (qdiff != 0) { if ((fQualificationAdjustments & qdiff) == 0) return -1; diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/FunctionCost.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/FunctionCost.java index b4fe8e74b8a..df6751d49bb 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/FunctionCost.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/FunctionCost.java @@ -155,7 +155,7 @@ class FunctionCost { } else if (!isTemplate && otherIsTemplate) { haveBetter = true; } else if (isTemplate && otherIsTemplate) { - int order = CPPTemplates.orderTemplateFunctions(otherAsTemplate, asTemplate); + int order = CPPTemplates.orderFunctionTemplates(otherAsTemplate, asTemplate); if (order < 0) { haveBetter= true; } else if (order > 0) { 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 ec49fbce932..a40b35f607a 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 @@ -38,6 +38,7 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPPointerToMemberType; import org.eclipse.cdt.core.dom.ast.cpp.ICPPReferenceType; import org.eclipse.cdt.core.dom.ast.cpp.ICPPSpecialization; import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateArgument; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateInstance; import org.eclipse.cdt.core.index.IIndexBinding; import org.eclipse.cdt.core.parser.Keywords; import org.eclipse.cdt.core.parser.util.ArrayUtil; @@ -577,4 +578,50 @@ public class SemanticUtil { return -1; } + + public static boolean containsUniqueTypeForParameterPack(IType type) { + if (type instanceof ICPPFunctionType) { + final ICPPFunctionType ft = (ICPPFunctionType) type; + if (containsUniqueTypeForParameterPack(ft.getReturnType())) + return true; + + for (IType pt : ft.getParameterTypes()) { + if (containsUniqueTypeForParameterPack(pt)) + return true; + } + return false; + } + + if (type instanceof ICPPPointerToMemberType) { + if (containsUniqueTypeForParameterPack(((ICPPPointerToMemberType) type).getMemberOfClass())) + return true; + } + + if (type instanceof IBinding) { + IBinding owner = ((IBinding) type).getOwner(); + if (owner instanceof IType) { + if (containsUniqueTypeForParameterPack((IType) owner)) + return true; + } + } + + if (type instanceof ICPPTemplateInstance) { + ICPPTemplateArgument[] args = ((ICPPTemplateInstance) type).getTemplateArguments(); + for (ICPPTemplateArgument arg : args) { + if (containsUniqueTypeForParameterPack(arg.getTypeValue())) + return true; + } + } + + if (type instanceof ITypeContainer) { + final ITypeContainer tc = (ITypeContainer) type; + final IType nestedType= tc.getType(); + return containsUniqueTypeForParameterPack(nestedType); + } + + if (type instanceof UniqueType) { + return ((UniqueType) type).isForParameterPack(); + } + return false; + } } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/TemplateArgumentDeduction.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/TemplateArgumentDeduction.java index f259671f8a8..a7fd66ad305 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/TemplateArgumentDeduction.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/TemplateArgumentDeduction.java @@ -19,6 +19,7 @@ import java.util.HashSet; import java.util.List; import java.util.Set; +import org.eclipse.cdt.core.dom.ast.ASTTypeUtil; import org.eclipse.cdt.core.dom.ast.DOMException; import org.eclipse.cdt.core.dom.ast.IASTExpression.ValueCategory; import org.eclipse.cdt.core.dom.ast.IArrayType; @@ -35,6 +36,7 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPBasicType; import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassTemplate; import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassTemplatePartialSpecialization; import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassType; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPFunction; import org.eclipse.cdt.core.dom.ast.cpp.ICPPFunctionTemplate; import org.eclipse.cdt.core.dom.ast.cpp.ICPPParameterPackType; import org.eclipse.cdt.core.dom.ast.cpp.ICPPPointerToMemberType; @@ -97,7 +99,7 @@ public class TemplateArgumentDeduction { map.put(tmplParam, pack); } - if (!deduceFromFunctionArgs(template, fnArgs, argIsLValue, map, false)) + if (!deduceFromFunctionArgs(template, fnArgs, argIsLValue, map)) return null; List result= new ArrayList(numTmplParams); @@ -236,7 +238,7 @@ public class TemplateArgumentDeduction { * returns false if there is no mapping. */ static boolean deduceFromFunctionArgs(ICPPFunctionTemplate template, List fnArgs, List argCats, - CPPTemplateParameterMap map, boolean checkExactMatch) { + CPPTemplateParameterMap map) { try { IType[] fnPars = template.getType().getParameterTypes(); final int fnParCount = fnPars.length; @@ -246,7 +248,7 @@ public class TemplateArgumentDeduction { final ICPPTemplateParameter[] tmplPars = template.getTemplateParameters(); TemplateArgumentDeduction deduct= new TemplateArgumentDeduction(tmplPars, map, new CPPTemplateParameterMap(fnParCount), 0); IType fnParPack= null; - for (int j= 0; j < fnArgs.size(); j++) { + argLoop: for (int j= 0; j < fnArgs.size(); j++) { IType par; if (fnParPack != null) { par= fnParPack; @@ -255,7 +257,7 @@ public class TemplateArgumentDeduction { par= fnPars[j]; if (par instanceof ICPPParameterPackType) { if (j != fnParCount - 1) - continue; // non-deduced context + continue argLoop; // Non-deduced context par= fnParPack= ((ICPPParameterPackType) par).getType(); deduct= new TemplateArgumentDeduction(deduct, fnArgs.size() - j); @@ -268,14 +270,12 @@ public class TemplateArgumentDeduction { if (!CPPTemplates.isValidType(par)) return false; - boolean isDependentPar= CPPTemplates.isDependentType(par); - if (checkExactMatch || isDependentPar) { + if (CPPTemplates.isDependentType(par)) { IType arg = fnArgs.get(j); par= SemanticUtil.getNestedType(par, SemanticUtil.TDEF); // adjustParameterType preserves typedefs // C++0x: 14.9.2.1-1 if (arg instanceof InitializerListType) { - assert !checkExactMatch; par= SemanticUtil.getNestedType(par, TDEF | REF | CVTYPE); // Check if this is a deduced context @@ -285,23 +285,44 @@ public class TemplateArgumentDeduction { IType[] types = initListType.getExpressionTypes(); ValueCategory[] valueCats = initListType.getValueCategories(); for (int i = 0; i < types.length; i++) { - if (!deduceFromFunctionArg(inner, types[i], valueCats[i], checkExactMatch, isDependentPar, deduct)) + if (!deduceFromFunctionArg(inner, types[i], valueCats[i], deduct)) return false; } } - continue; - } - - // 14.8.2.1-2 - ValueCategory cat= argCats != null ? argCats.get(j) : LVALUE; - if (!deduceFromFunctionArg(par, arg, cat, checkExactMatch, isDependentPar, deduct)) { - return false; + } else if (arg instanceof FunctionSetType) { + // 14.8.2.1-6 Handling of overloaded function sets + ICPPFunction[] fs= ((FunctionSetType) arg).getFunctionSet(); + for (ICPPFunction f : fs) { + if (f instanceof ICPPFunctionTemplate) + continue argLoop; // Non-deduced context + } + + // Do trial deduction + CPPTemplateParameterMap success= null; + Set handled= new HashSet(); + for (ICPPFunction f : fs) { + arg= f.getType(); + if (handled.add(ASTTypeUtil.getType(arg, true))) { + final CPPTemplateParameterMap state = deduct.saveState(); + if (deduceFromFunctionArg(par, arg, argCats.get(j), deduct)) { + if (success != null) { + deduct.restoreState(state); + continue argLoop; // Non-deduced context + } + success= deduct.saveState(); + } + deduct.restoreState(state); + } + } + if (success == null) + return false; + deduct.restoreState(success); + } else { + if (!deduceFromFunctionArg(par, arg, argCats.get(j), deduct)) + return false; } } } - // Bug 309564: For partial ordering not all arguments need to be deduced - if (checkExactMatch) - return true; if (!deduct.fExplicitArgs.mergeToExplicit(deduct.fDeducedArgs)) return false; @@ -312,7 +333,7 @@ public class TemplateArgumentDeduction { return false; } - private static boolean deduceFromFunctionArg(IType par, IType arg, ValueCategory valueCat, boolean checkExactMatch, boolean isDependentPar, TemplateArgumentDeduction deduct) throws DOMException { + private static boolean deduceFromFunctionArg(IType par, IType arg, ValueCategory valueCat, TemplateArgumentDeduction deduct) throws DOMException { boolean isReferenceTypeParameter= false; if (par instanceof ICPPReferenceType) { // If P is an rvalue reference to a cv-unqualified template parameter and the argument is an @@ -330,61 +351,113 @@ public class TemplateArgumentDeduction { arg= getArgumentTypeForDeduction(arg, false); } - if (!checkExactMatch) { - // 14.8.2.1-3 - CVQualifier cvPar= SemanticUtil.getCVQualifier(par); - CVQualifier cvArg= SemanticUtil.getCVQualifier(arg); - if (cvPar == cvArg || (isReferenceTypeParameter && cvPar.isAtLeastAsQualifiedAs(cvArg))) { - IType pcheck= SemanticUtil.getNestedType(par, CVTYPE); - if (!(pcheck instanceof ICPPTemplateParameter)) { - par= pcheck; - arg= SemanticUtil.getNestedType(arg, CVTYPE); - IType argcheck= arg; - if (par instanceof IPointerType && arg instanceof IPointerType) { - pcheck= ((IPointerType) par).getType(); - argcheck= ((IPointerType) arg).getType(); - if (pcheck instanceof ICPPTemplateParameter) { - pcheck= null; + // 14.8.2.1-3 + CVQualifier cvPar= SemanticUtil.getCVQualifier(par); + CVQualifier cvArg= SemanticUtil.getCVQualifier(arg); + if (cvPar == cvArg || (isReferenceTypeParameter && cvPar.isAtLeastAsQualifiedAs(cvArg))) { + IType pcheck= SemanticUtil.getNestedType(par, CVTYPE); + if (!(pcheck instanceof ICPPTemplateParameter)) { + par= pcheck; + arg= SemanticUtil.getNestedType(arg, CVTYPE); + IType argcheck= arg; + if (par instanceof IPointerType && arg instanceof IPointerType) { + pcheck= ((IPointerType) par).getType(); + argcheck= ((IPointerType) arg).getType(); + if (pcheck instanceof ICPPTemplateParameter) { + pcheck= null; + } else { + cvPar= SemanticUtil.getCVQualifier(pcheck); + cvArg= SemanticUtil.getCVQualifier(argcheck); + if (cvPar.isAtLeastAsQualifiedAs(cvArg)) { + pcheck= SemanticUtil.getNestedType(pcheck, CVTYPE); + argcheck= SemanticUtil.getNestedType(argcheck, CVTYPE); } else { - cvPar= SemanticUtil.getCVQualifier(pcheck); - cvArg= SemanticUtil.getCVQualifier(argcheck); - if (cvPar.isAtLeastAsQualifiedAs(cvArg)) { - pcheck= SemanticUtil.getNestedType(pcheck, CVTYPE); - argcheck= SemanticUtil.getNestedType(argcheck, CVTYPE); - } else { - pcheck= null; - } + pcheck= null; } } - if (pcheck instanceof ICPPTemplateInstance && argcheck instanceof ICPPClassType) { - ICPPTemplateInstance pInst = (ICPPTemplateInstance) pcheck; - ICPPClassTemplate pTemplate= getPrimaryTemplate(pInst); - if (pTemplate != null) { - ICPPClassType aInst= findBaseInstance((ICPPClassType) argcheck, pTemplate, CPPSemantics.MAX_INHERITANCE_DEPTH); - if (aInst != null && aInst != argcheck) { - par= pcheck; - arg= aInst; - } + } + if (pcheck instanceof ICPPTemplateInstance && argcheck instanceof ICPPClassType) { + ICPPTemplateInstance pInst = (ICPPTemplateInstance) pcheck; + ICPPClassTemplate pTemplate= getPrimaryTemplate(pInst); + if (pTemplate != null) { + ICPPClassType aInst= findBaseInstance((ICPPClassType) argcheck, pTemplate, CPPSemantics.MAX_INHERITANCE_DEPTH); + if (aInst != null && aInst != argcheck) { + par= pcheck; + arg= aInst; } } } } } - if (isDependentPar && !deduct.fromType(par, arg, true)) { - return false; + return deduct.fromType(par, arg, true); + } + + /** + * Deduces the mapping for the template parameters from the function parameters, + * returns false if there is no mapping. + */ + static int deduceForPartialOrdering(ICPPTemplateParameter[] tmplPars, IType[] fnPars, IType[] fnArgs) { + try { + final int fnParCount = fnPars.length; + final int fnArgCount = fnArgs.length; + int result= 0; + TemplateArgumentDeduction deduct= new TemplateArgumentDeduction(tmplPars, new CPPTemplateParameterMap(0), new CPPTemplateParameterMap(fnParCount), 0); + IType fnParPack= null; + for (int j= 0; j < fnArgCount; j++) { + IType par; + if (fnParPack != null) { + par= fnParPack; + deduct.incPackOffset(); + } else { + if (j >= fnParCount) + return result; + + par= fnPars[j]; + if (par instanceof ICPPParameterPackType) { + if (j != fnParCount - 1) + continue; // non-deduced context + + par= fnParPack= ((ICPPParameterPackType) par).getType(); + deduct= new TemplateArgumentDeduction(deduct, fnArgs.length - j); + } + } + + IType arg = fnArgs[j]; + int cmpSpecialized= deduceForPartialOrdering(par, arg, deduct); + if (cmpSpecialized < 0) + return cmpSpecialized; + if (cmpSpecialized > 0) + result= cmpSpecialized; + } + return result; + } catch (DOMException e) { } - if (checkExactMatch) { - IType instantiated= CPPTemplates.instantiateType(par, deduct.fDeducedArgs, deduct.fPackOffset, null); - if (!instantiated.isSameType(arg)) - return false; + return -1; + } + + private static int deduceForPartialOrdering(IType par, IType arg, TemplateArgumentDeduction deduct) throws DOMException { + par= getNestedType(par, TDEF); + arg= getNestedType(arg, TDEF); + boolean isMoreCVQualified= false; + if (par instanceof ICPPReferenceType && arg instanceof ICPPReferenceType) { + par= getNestedType(par, REF | TDEF); + arg= getNestedType(arg, REF | TDEF); + CVQualifier cvp= getCVQualifier(par); + CVQualifier cva= getCVQualifier(arg); + isMoreCVQualified= cva.isMoreQualifiedThan(cvp); } - return true; + par= getNestedType(par, TDEF | REF | ALLCVQ); + arg= getNestedType(arg, TDEF | REF | ALLCVQ); + + if (!deduct.fromType(par, arg, false)) + return -1; + + return isMoreCVQualified ? 1 : 0; } /** * 14.8.2.1.3 If P is a class and has the form template-id, then A can be a derived class of the deduced A. - * @throws DOMException */ private static ICPPClassType findBaseInstance(ICPPClassType a, ICPPClassTemplate pTemplate, int maxdepth) throws DOMException { if (a instanceof ICPPTemplateInstance) { @@ -519,6 +592,14 @@ public class TemplateArgumentDeduction { fPackSize= packSize; fPackOffset= packSize > 0 ? 0 : -1; } + + private CPPTemplateParameterMap saveState() { + return new CPPTemplateParameterMap(fDeducedArgs); + } + + private void restoreState(CPPTemplateParameterMap saved) { + fDeducedArgs= saved; + } private void incPackOffset() { fPackOffset++; @@ -535,15 +616,21 @@ public class TemplateArgumentDeduction { if (p.isNonTypeValue()) { IValue tval= p.getNonTypeValue(); - int parId= Value.isTemplateParameter(tval); - if (parId >= 0) { - ICPPTemplateArgument old= fDeducedArgs.getArgument(parId, fPackOffset); - if (old == null) { - return deduce(parId, a); + if (Value.referencesTemplateParameter(tval)) { + int parId= Value.isTemplateParameter(tval); + if (parId >= 0) { + if (!p.getTypeOfNonTypeValue().isSameType(a.getTypeOfNonTypeValue())) + return false; + ICPPTemplateArgument old= fDeducedArgs.getArgument(parId, fPackOffset); + if (old == null) { + return deduce(parId, a); + } + return old.isSameValue(a); + } else { + // Non-deduced context + return true; } - return old.isSameValue(a); } - IValue sval= a.getNonTypeValue(); return tval.equals(sval); } @@ -758,6 +845,8 @@ public class TemplateArgumentDeduction { return false; return fDeducedArgs.putPackElement(parID, fPackOffset, arg, fPackSize); } + if (SemanticUtil.containsUniqueTypeForParameterPack(arg.getTypeValue())) + return false; fDeducedArgs.put(parID, arg); return true; } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/UniqueType.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/UniqueType.java new file mode 100644 index 00000000000..cde78f029fc --- /dev/null +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/UniqueType.java @@ -0,0 +1,35 @@ +/* + * UniqueType.java + * Created on 04.10.2010 + * + * Copyright 2010 Wind River Systems, Inc. All rights reserved. + */ + +package org.eclipse.cdt.internal.core.dom.parser.cpp.semantics; + +import org.eclipse.cdt.core.dom.ast.IType; + +/** + * Used for computing the partial ordering of function templates. + */ +class UniqueType implements IType { + + private boolean fForParameterPack; + + public UniqueType(boolean forParameterPack) { + fForParameterPack= forParameterPack; + } + + public boolean isSameType(IType type) { + return type == this; + } + + public boolean isForParameterPack() { + return fForParameterPack; + } + + @Override + public Object clone() { + throw new UnsupportedOperationException(); + } +}