diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2TemplateTests.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2TemplateTests.java index bb44225aa05..e5ba1b9bbc2 100644 --- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2TemplateTests.java +++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2TemplateTests.java @@ -14,6 +14,8 @@ *******************************************************************************/ package org.eclipse.cdt.core.parser.tests.ast2; +import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.TDEF; +import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.getNestedType; import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.getUltimateType; import junit.framework.TestSuite; @@ -4365,7 +4367,7 @@ public class AST2TemplateTests extends AST2BaseTest { assertEquals("void (#0 (* ...)())", ASTTypeUtil.getType(f.getType(), true)); assertTrue(f.getParameters()[0].isParameterPack()); f= bh.assertNonProblem("f4", 2); - assertEquals("void (int (& ...)[#0])", ASTTypeUtil.getType(f.getType(), true)); + assertEquals("void (int (& ...)[`0])", ASTTypeUtil.getType(f.getType(), true)); assertTrue(f.getParameters()[0].isParameterPack()); f= bh.assertNonProblem("f5", 2); assertEquals("void (#0 ...)", ASTTypeUtil.getType(f.getType(), true)); @@ -4397,6 +4399,32 @@ public class AST2TemplateTests extends AST2BaseTest { assertTrue(tp.isParameterPack()); } + // template class CT : public Pack... { + // void mem() throw(Pack...); + // }; + // struct A {int a;}; + // struct B {int b;}; + // + // void test() { + // CT c; + // c.a= 1; + // c.b= 1; + // c.mem(); + // } + public void testParameterPackExpansions_280909() throws Exception { + final String code= getAboveComment(); + parseAndCheckBindings(code, ParserLanguage.CPP); + BindingAssertionHelper bh= new BindingAssertionHelper(code, true); + ICPPField field= bh.assertNonProblem("a= 1", 1); + field= bh.assertNonProblem("b= 1", 1); + + ICPPMethod meth= bh.assertNonProblem("mem();", 3); + IType[] spec= meth.getExceptionSpecification(); + assertEquals(2, spec.length); + assertEquals("A", ASTTypeUtil.getType(spec[0])); + assertEquals("B", ASTTypeUtil.getType(spec[1])); + } + // template void f1(T*...); // template void f2(T*...); public void testTemplateParameterPacksAmbiguity_280909() throws Exception { @@ -4426,7 +4454,7 @@ public class AST2TemplateTests extends AST2BaseTest { // void g() { // f(add, subtract); // } - public void _testVariadicTemplateExamples_280909b() throws Exception { + public void testVariadicTemplateExamples_280909b() throws Exception { final String code= getAboveComment(); parseAndCheckBindings(code, ParserLanguage.CPP); } @@ -4474,7 +4502,7 @@ public class AST2TemplateTests extends AST2BaseTest { // Y ya; // ill-formed: a template parameter pack does not match a template parameter // Y yb; // ill-formed: a template parameter pack does not match a template parameter // Y yc; // okay - public void _testVariadicTemplateExamples_280909f() throws Exception { + public void testVariadicTemplateExamples_280909f() throws Exception { final String code= getAboveComment(); BindingAssertionHelper bh= new BindingAssertionHelper(code, true); bh.assertNonProblem("X", 4); @@ -4539,13 +4567,13 @@ public class AST2TemplateTests extends AST2BaseTest { // f("aa",3.0); // error: X cannot be deduced // f2(); // okay // } - public void _testVariadicTemplateExamples_280909i() throws Exception { + public void testVariadicTemplateExamples_280909i() throws Exception { final String code= getAboveComment(); BindingAssertionHelper bh= new BindingAssertionHelper(code, true); bh.assertNonProblem("f", 0); bh.assertNonProblem("f", 0); - bh.assertProblem("f", 0); - bh.assertNonProblem("f(", 1); + bh.assertNonProblem("f", 0); + bh.assertProblem("f(\"aa\",3.0)", 1); bh.assertNonProblem("f2", 0); } @@ -4553,19 +4581,19 @@ public class AST2TemplateTests extends AST2BaseTest { // void g() { // f(0, 0, 0); // Types is the sequence int*, float*, int // } - public void _testVariadicTemplateExamples_280909j() throws Exception { + public void testVariadicTemplateExamples_280909j() throws Exception { final String code= getAboveComment(); parseAndCheckBindings(code, ParserLanguage.CPP); } // template void f(Types&...); - // template void g(T1, Types...); + // template void g(T1, Types...); // void h(int x, float& y) { // const int z = x; // f(x, y, z); // Types is deduced to int, float, const int // g(x, y, z); // T1 is deduced to int, Types is deduced to float, int // } - public void _testVariadicTemplateExamples_280909k() throws Exception { + public void testVariadicTemplateExamples_280909k() throws Exception { final String code= getAboveComment(); parseAndCheckBindings(code, ParserLanguage.CPP); } @@ -4574,11 +4602,13 @@ public class AST2TemplateTests extends AST2BaseTest { // template void g(Tuple); // #1 // template void g(Tuple); // #2 // template void g(Tuple); // #3 - // g(Tuple<>()); // calls #1 - // g(Tuple()); // calls #2 - // g(Tuple()); // calls #3 - // g(Tuple()); // calls #3 - public void _testVariadicTemplateExamples_280909m() throws Exception { + // void test() { + // g(Tuple<>()); // calls #1 + // g(Tuple()); // calls #2 + // g(Tuple()); // calls #3 + // g(Tuple()); // calls #3 + // } + public void testVariadicTemplateExamples_280909m() throws Exception { final String code= getAboveComment(); parseAndCheckBindings(code, ParserLanguage.CPP); BindingAssertionHelper bh= new BindingAssertionHelper(code, true); @@ -4586,21 +4616,21 @@ public class AST2TemplateTests extends AST2BaseTest { ICPPFunction g2= bh.assertNonProblem("g(Tuple)", 1); ICPPFunction g3= bh.assertNonProblem("g(Tuple)", 1); - ICPPFunction x= bh.assertNonProblem("g(Tuple<>())", 1); - assertSame(g1, x); + ICPPTemplateInstance x= bh.assertNonProblem("g(Tuple<>())", 1); + assertSame(g1, x.getTemplateDefinition()); x= bh.assertNonProblem("g(Tuple())", 1); - assertSame(g2, x); + assertSame(g2, x.getTemplateDefinition()); x= bh.assertNonProblem("g(Tuple())", 1); - assertSame(g3, x); + assertSame(g3, x.getTemplateDefinition()); x= bh.assertNonProblem("g(Tuple())", 1); - assertSame(g3, x); + assertSame(g3, x.getTemplateDefinition()); } // template struct X { }; // template struct X { }; // template struct Y { }; // template struct Y { }; - // template int f (void ()(Types...)); + // template int f (void (*)(Types...)); // void g(int, float); // X x1; // uses primary template // X x2; // uses partial specialization, ArgTypes contains float, double @@ -4609,7 +4639,7 @@ public class AST2TemplateTests extends AST2BaseTest { // Y y2; // uses partial specialization. T is int&, Types contains float, double // Y y3; // uses primary template, Types contains int, float, double // int fv = f(g); // okay, Types contains int, float - public void _testVariadicTemplateExamples_280909n() throws Exception { + public void testVariadicTemplateExamples_280909n() throws Exception { final String code= getAboveComment(); parseAndCheckBindings(code, ParserLanguage.CPP); } @@ -4622,7 +4652,7 @@ public class AST2TemplateTests extends AST2BaseTest { // f(1, 2, 3); // calls #2 // f(1, 2); // calls #3; non-variadic template #3 is // } // more specialized than the variadic templates #1 and #2 - public void _testVariadicTemplateExamples_280909o() throws Exception { + public void testVariadicTemplateExamples_280909o() throws Exception { final String code= getAboveComment(); parseAndCheckBindings(code, ParserLanguage.CPP); BindingAssertionHelper bh= new BindingAssertionHelper(code, true); @@ -4630,12 +4660,12 @@ public class AST2TemplateTests extends AST2BaseTest { ICPPFunction f2= bh.assertNonProblem("f(T1 a1, Args... args)", 1); ICPPFunction f3= bh.assertNonProblem("f(T1 a2, T2 a2)", 1); - ICPPFunction x= bh.assertNonProblem("f()", 1); - assertSame(f1, x); + ICPPTemplateInstance x= bh.assertNonProblem("f()", 1); + assertSame(f1, x.getTemplateDefinition()); x= bh.assertNonProblem("f(1, 2, 3)", 1); - assertSame(f2, x); + assertSame(f2, x.getTemplateDefinition()); x= bh.assertNonProblem("f(1, 2)", 1); - assertSame(f3, x); + assertSame(f3, x.getTemplateDefinition()); } // template struct Tuple { }; @@ -4645,7 +4675,7 @@ public class AST2TemplateTests extends AST2BaseTest { // Tuple t2; // Types contains two arguments: int and float // Tuple<0> error; // Error: 0 is not a type // } - public void _testVariadicTemplateExamples_280909p() throws Exception { + public void testVariadicTemplateExamples_280909p() throws Exception { final String code= getAboveComment(); BindingAssertionHelper bh= new BindingAssertionHelper(code, true); bh.assertNonProblem("Tuple<>", 0); @@ -4660,7 +4690,7 @@ public class AST2TemplateTests extends AST2BaseTest { // f(1); // okay: args contains one int argument // f(2, 1.0); // okay: args contains two arguments, an int and a double // } - public void _testVariadicTemplateExamples_280909q() throws Exception { + public void testVariadicTemplateExamples_280909q() throws Exception { final String code= getAboveComment(); parseAndCheckBindings(code, ParserLanguage.CPP); } @@ -4686,21 +4716,28 @@ public class AST2TemplateTests extends AST2BaseTest { // typedef zip::with::type T2; // // error: different number of arguments specified // // for Args1 and Args2 + // template void f(Args... args) {} + // template void h(Args... args) {} // template void g(Args... args) { - // f(const cast(&args)...); // okay: ‘‘Args’’ and ‘‘args’’ are expanded + // f(const_cast(&args)...); // okay: ‘‘Args’’ and ‘‘args’’ are expanded // f(5 ...); // error: pattern does not contain any parameter packs // f(args); // error: parameter pack ”args” is not expanded // f(h(args...) + args...); // okay: first ‘‘args’’ expanded within h, second ‘‘args’’ expanded within f. // } - public void _testVariadicTemplateExamples_280909s() throws Exception { + public void testVariadicTemplateExamples_280909s() throws Exception { final String code= getAboveComment(); BindingAssertionHelper bh= new BindingAssertionHelper(code, true); ITypedef td= bh.assertNonProblem("T1;", 2); - assertEquals("Tuple, Pair >", ASTTypeUtil.getType(td, true)); - bh.assertProblem("zip::with::type", 0); - bh.assertNonProblem("f(const cast(&args)...)", 1); - bh.assertProblem("f(5 ...)", 1); - bh.assertProblem("f(args)", 1); - bh.assertNonProblem("f(h(args...) + args...)", 1); + IType type = getNestedType(td, TDEF); + assertEquals("Tuple,Pair>", ASTTypeUtil.getType(type, false)); + td= bh.assertNonProblem("zip::with::type", 0); + type = getNestedType(td, TDEF); + assertTrue(type instanceof IProblemBinding); + + ICPPUnknownBinding ub; + ub= bh.assertNonProblem("f(const_cast(&args)...)", 1); + ub= bh.assertNonProblem("f(5 ...)", 1); // no diagnostics in CDT, treated as unknown function. + ub= bh.assertNonProblem("f(args)", 1); // no diagnostics in CDT + ub= bh.assertNonProblem("f(h(args...) + args...)", 1); } } diff --git a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/model/ext/StructureTemplateHandle.java b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/model/ext/StructureTemplateHandle.java index f19162f112f..1e2f1ff8726 100644 --- a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/model/ext/StructureTemplateHandle.java +++ b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/model/ext/StructureTemplateHandle.java @@ -11,6 +11,9 @@ *******************************************************************************/ package org.eclipse.cdt.internal.core.model.ext; +import java.util.ArrayList; +import java.util.List; + import org.eclipse.cdt.core.dom.ast.ASTTypeUtil; import org.eclipse.cdt.core.dom.ast.DOMException; import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassSpecialization; @@ -55,13 +58,21 @@ public class StructureTemplateHandle extends StructureHandle implements IStructu fTemplate= new Template(classBinding.getName()); ICPPTemplateParameterMap map = classBinding.getTemplateParameterMap(); ICPPTemplateParameter[] tpars = ct.getTemplateParameters(); - String[] args= new String[tpars.length]; - for (int i = 0; i < tpars.length; i++) { - ICPPTemplateParameter par = tpars[i]; + List args= new ArrayList(tpars.length); + for (ICPPTemplateParameter par : tpars) { + if (par.isParameterPack()) { + ICPPTemplateArgument[] pack= map.getPackExpansion(par); + if (pack != null) { + for (ICPPTemplateArgument p : pack) { + args.add(ASTTypeUtil.getArgumentString(p, false)); + } + continue; + } + } ICPPTemplateArgument arg = map.getArgument(par); - args[i]= arg == null ? par.getName() : ASTTypeUtil.getArgumentString(arg, false); + args.add(arg == null ? par.getName() : ASTTypeUtil.getArgumentString(arg, false)); } - fTemplate.setTemplateInfo(null, args); + fTemplate.setTemplateInfo(null, args.toArray(new String[args.size()])); } public int getNumberOfTemplateParameters() { diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/cpp/ICPPTemplateArgument.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/cpp/ICPPTemplateArgument.java index bbe91770082..cda584b37a0 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/cpp/ICPPTemplateArgument.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/cpp/ICPPTemplateArgument.java @@ -60,4 +60,16 @@ public interface ICPPTemplateArgument { * Checks whether two arguments denote the same value. */ boolean isSameValue(ICPPTemplateArgument arg); + + /** + * Returns whether this template argument is a pack expansion or not. + * @since 5.2 + */ + boolean isPackExpansion(); + + /** + * Returns the expansion pattern, if this is a pack expansion, or null otherwise. + * @since 5.2 + */ + ICPPTemplateArgument getExpansionPattern(); } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/cpp/ICPPTemplateParameterMap.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/cpp/ICPPTemplateParameterMap.java index aa55f5fc056..a0ccd0e9aec 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/cpp/ICPPTemplateParameterMap.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/cpp/ICPPTemplateParameterMap.java @@ -12,7 +12,8 @@ package org.eclipse.cdt.core.dom.ast.cpp; /** - * Models the mapping of template parameters to values. + * Models the mapping of template parameters to values, or pack-expansions. + * * @since 5.1 * @noextend This interface is not intended to be extended by clients. * @noimplement This interface is not intended to be implemented by clients. @@ -27,10 +28,25 @@ public interface ICPPTemplateParameterMap { /** * Returns the value for the template parameter in the map, or null if - * the parameter is not mapped. + * the parameter is not mapped or the parameter is a parameter pack. */ public ICPPTemplateArgument getArgument(ICPPTemplateParameter param); + + /** + * Returns the values for the template parameter pack with the given id in the map, + * or null if the parameter is not mapped or is not a parameter pack. + * @since 5.2 + */ + public ICPPTemplateArgument[] getPackExpansion(int paramID); + + /** + * Returns the values for the template parameter pack in the map, or null if the + * parameter is not mapped or is no parameter pack. + * @since 5.2 + */ + public ICPPTemplateArgument[] getPackExpansion(ICPPTemplateParameter param); + /** * Returns the array of template parameter positions, for which a mapping exists. */ 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 665fd600093..b1ec1a7c997 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 @@ -46,10 +46,12 @@ public class Value implements IValue { public static final int MAX_RECURSION_DEPTH = 25; public final static IValue UNKNOWN= new Value("".toCharArray(), ICPPUnknownBinding.EMPTY_UNKNOWN_BINDING_ARRAY); //$NON-NLS-1$ public final static IValue NOT_INITIALIZED= new Value("<__>".toCharArray(), ICPPUnknownBinding.EMPTY_UNKNOWN_BINDING_ARRAY); //$NON-NLS-1$ + private static final int[] NO_INT = {}; private static final String SCOPE_OP = "::"; //$NON-NLS-1$ private static final char UNIQUE_CHAR = '_'; private static final char TEMPLATE_PARAM_CHAR = '#'; + private static final char TEMPLATE_PARAM_PACK_CHAR = '`'; private static final char REFERENCE_CHAR = '&'; private static final char UNARY_OP_CHAR = '$'; private static final char BINARY_OP_CHAR = '@'; @@ -69,13 +71,17 @@ public class Value implements IValue { private static class Reevaluation { public final char[] fExpression; + private int fPackOffset; public int pos=0; public final Map fUnknownSigs; public final List fUnknowns; public final IBinding[] fResolvedUnknown; public final ICPPTemplateParameterMap fMap; - public Reevaluation(char[] expr, Map unknownSigs, List unknowns, IBinding[] resolvedUnknowns, ICPPTemplateParameterMap map) { + + public Reevaluation(char[] expr, int packOffset, Map unknownSigs, + List unknowns, IBinding[] resolvedUnknowns, ICPPTemplateParameterMap map) { fExpression= expr; + fPackOffset= packOffset; fUnknownSigs= unknownSigs; fUnknowns= unknowns; fResolvedUnknown= resolvedUnknowns; @@ -189,25 +195,26 @@ public class Value implements IValue { * Creates a value representing the given template parameter. */ public static IValue create(ICPPTemplateNonTypeParameter tntp) { - final String expr = createTemplateParamExpression(tntp.getParameterID()); + final String expr = createTemplateParamExpression(tntp.getParameterID(), tntp.isParameterPack()); return new Value(expr.toCharArray(), ICPPUnknownBinding.EMPTY_UNKNOWN_BINDING_ARRAY); } - private static String createTemplateParamExpression(int id) { + private static String createTemplateParamExpression(int id, boolean isPack) { StringBuilder buf= new StringBuilder(); - buf.append(TEMPLATE_PARAM_CHAR); + buf.append(isPack ? TEMPLATE_PARAM_PACK_CHAR : TEMPLATE_PARAM_CHAR); buf.append(Integer.toHexString(id)); return buf.toString(); } /** - * Tests whether the value is a template parameter, returns the parameter id of the - * parameter, or -1 if it is not a template parameter. + * Tests whether the value is a template parameter (or parameter pack), + * returns the parameter id of the parameter, or -1 if it is not a template parameter. */ public static int isTemplateParameter(IValue tval) { final char[] rep= tval.getInternalExpression(); if (rep.length > 0) { - if (rep[0] == TEMPLATE_PARAM_CHAR) { + final char c = rep[0]; + if (c == TEMPLATE_PARAM_CHAR || c == TEMPLATE_PARAM_PACK_CHAR) { for (int i = 1; i < rep.length; i++) { if (rep[i] == SEPARATOR) return -1; @@ -227,7 +234,7 @@ public class Value implements IValue { public static boolean referencesTemplateParameter(IValue tval) { final char[] rep= tval.getInternalExpression(); for (char element : rep) { - if (element == TEMPLATE_PARAM_CHAR) + if (element == TEMPLATE_PARAM_CHAR || element == TEMPLATE_PARAM_PACK_CHAR) return true; } return false; @@ -239,12 +246,50 @@ public class Value implements IValue { public static boolean isDependentValue(IValue nonTypeValue) { final char[] rep= nonTypeValue.getInternalExpression(); for (final char c : rep) { - if (c == REFERENCE_CHAR || c == TEMPLATE_PARAM_CHAR) + if (c == REFERENCE_CHAR || c == TEMPLATE_PARAM_CHAR || c == TEMPLATE_PARAM_PACK_CHAR) return true; } return false; } + /** + * Collects all references to parameter packs. + */ + public static int[] getParameterPackReferences(IValue value) { + final char[] rep= value.getInternalExpression(); + int result= -1; + List array= null; + for (int i=0; i(2); + array.add(result); + } + array.add(ref); + } + } catch (UnknownValueException e) { + } + } + } + if (array != null) { + int[] ra= new int[array.size()]; + for (int i = 0; i < ra.length; i++) { + ra[i]= array.get(i); + } + return ra; + } + if (result != -1) + return new int[] {result}; + + return NO_INT; + } + /** * Creates the value for an expression. */ @@ -371,8 +416,10 @@ public class Value implements IValue { if (b instanceof IType) { throw UNKNOWN_EX; } - if (b instanceof ICPPTemplateNonTypeParameter) - return createTemplateParamExpression(((ICPPTemplateNonTypeParameter) b).getParameterID()); + if (b instanceof ICPPTemplateNonTypeParameter) { + final ICPPTemplateNonTypeParameter tp = (ICPPTemplateNonTypeParameter) b; + return createTemplateParamExpression(tp.getParameterID(), tp.isParameterPack()); + } if (b instanceof ICPPUnknownBinding) { return createReference((ICPPUnknownBinding) b, unknownSigs, unknowns); @@ -591,11 +638,11 @@ public class Value implements IValue { return BINARY_OP_CHAR + op + SEPARATOR + o1.toString() + SEPARATOR + o2.toString(); } - public static IValue reevaluate(IValue val, IBinding[] resolvedUnknowns, ICPPTemplateParameterMap map, int maxdepth) { + public static IValue reevaluate(IValue val, int packOffset, IBinding[] resolvedUnknowns, ICPPTemplateParameterMap map, int maxdepth) { try { Map unknownSigs= new HashMap(); List unknown= new ArrayList(); - Reevaluation reeval= new Reevaluation(val.getInternalExpression(), + Reevaluation reeval= new Reevaluation(val.getInternalExpression(), packOffset, unknownSigs, unknown, resolvedUnknowns, map); Object obj= reevaluate(reeval, maxdepth); @@ -672,7 +719,25 @@ public class Value implements IValue { throw UNKNOWN_EX; return evaluateValue(val, reeval.fUnknownSigs, reeval.fUnknowns); } - return createTemplateParamExpression(num); + return createTemplateParamExpression(num, false); + + case TEMPLATE_PARAM_PACK_CHAR: + num= parseHex(buf, idx+1); + reeval.nextSeperator(); + arg= null; + if (reeval.fPackOffset >= 0) { + ICPPTemplateArgument[] args= reeval.fMap.getPackExpansion(num); + if (args != null && reeval.fPackOffset < args.length) { + arg= args[reeval.fPackOffset]; + } + } + if (arg != null) { + IValue val= arg.getNonTypeValue(); + if (val == null) + throw UNKNOWN_EX; + return evaluateValue(val, reeval.fUnknownSigs, reeval.fUnknowns); + } + return createTemplateParamExpression(num, true); default: reeval.nextSeperator(); diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/AbstractCPPClassSpecializationScope.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/AbstractCPPClassSpecializationScope.java index 992a8805957..7f549f48bdd 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/AbstractCPPClassSpecializationScope.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/AbstractCPPClassSpecializationScope.java @@ -29,6 +29,8 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPConstructor; import org.eclipse.cdt.core.dom.ast.cpp.ICPPField; import org.eclipse.cdt.core.dom.ast.cpp.ICPPMethod; import org.eclipse.cdt.core.dom.ast.cpp.ICPPNamespace; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPParameterPackType; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateParameter; import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateParameterMap; import org.eclipse.cdt.core.index.IIndexFileSet; import org.eclipse.cdt.core.parser.util.ArrayUtil; @@ -125,10 +127,26 @@ public class AbstractCPPClassSpecializationScope implements ICPPClassSpecializat } else { final ICPPTemplateParameterMap tpmap = specialClass.getTemplateParameterMap(); for (ICPPBase base : bases) { - ICPPBase specBase = base.clone(); IBinding origClass = base.getBaseClass(); + if (origClass instanceof ICPPTemplateParameter && ((ICPPTemplateParameter) origClass).isParameterPack()) { + IType[] specClasses= CPPTemplates.instantiateTypes(new IType[]{new CPPParameterPackType((IType) origClass)}, tpmap, -1, specialClass); + if (specClasses.length == 1 && specClasses[0] instanceof ICPPParameterPackType) { + result= (ICPPBase[]) ArrayUtil.append(ICPPBase.class, result, base); + } else { + for (IType specClass : specClasses) { + ICPPBase specBase = base.clone(); + specClass = SemanticUtil.getUltimateType(specClass, false); + if (specClass instanceof IBinding && !(specClass instanceof IProblemBinding)) { + specBase.setBaseClass((IBinding) specClass); + result = (ICPPBase[]) ArrayUtil.append(ICPPBase.class, result, specBase); + } + } + } + continue; + } if (origClass instanceof IType) { - IType specClass= CPPTemplates.instantiateType((IType) origClass, tpmap, specialClass); + ICPPBase specBase = base.clone(); + IType specClass= CPPTemplates.instantiateType((IType) origClass, tpmap, -1, specialClass); specClass = SemanticUtil.getUltimateType(specClass, false); if (specClass instanceof IBinding && !(specClass instanceof IProblemBinding)) { specBase.setBaseClass((IBinding) specClass); diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTAmbiguousParameterDeclaration.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTAmbiguousParameterDeclaration.java index 4bcc7fbe8aa..a029fef9bdb 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTAmbiguousParameterDeclaration.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTAmbiguousParameterDeclaration.java @@ -25,8 +25,8 @@ import org.eclipse.cdt.internal.core.dom.parser.ASTAmbiguousNode; 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.IASTAmbiguousParameterDeclaration; +import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPTemplates; import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPVisitor; -import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil; import org.eclipse.core.runtime.Assert; /** @@ -57,7 +57,7 @@ public class CPPASTAmbiguousParameterDeclaration extends ASTAmbiguousNode implem IType t= CPPVisitor.createParameterType(fParameterDecl, true); if (!(t instanceof ICPPParameterPackType) || - !SemanticUtil.containsParameterPack(((ICPPParameterPackType) t).getType())) { + !CPPTemplates.containsParameterPack(((ICPPParameterPackType) t).getType())) { final ICPPASTDeclarator dtor = fParameterDecl.getDeclarator(); dtor.setDeclaresParameterPack(false); adjustOffsets(dtor); diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTPackExpansionExpression.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTPackExpansionExpression.java index 4bb26e48e9c..a8c8707411b 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTPackExpansionExpression.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTPackExpansionExpression.java @@ -13,10 +13,12 @@ package org.eclipse.cdt.internal.core.dom.parser.cpp; import org.eclipse.cdt.core.dom.ast.ASTVisitor; import org.eclipse.cdt.core.dom.ast.IASTExpression; import org.eclipse.cdt.core.dom.ast.IASTNode; +import org.eclipse.cdt.core.dom.ast.IProblemBinding; import org.eclipse.cdt.core.dom.ast.IType; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTPackExpansionExpression; 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; /** * Implementation of pack expansion expression. @@ -51,7 +53,11 @@ public class CPPASTPackExpansionExpression extends ASTNode implements ICPPASTPac } public IType getExpressionType() { - return new CPPParameterPackType(fPattern.getExpressionType()); + final IType type = fPattern.getExpressionType(); + if (type == null) + return new ProblemBinding(this, IProblemBinding.SEMANTIC_INVALID_TYPE, getRawSignatureChars()); + + return new CPPParameterPackType(type); } public boolean isLValue() { diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPClassTemplatePartialSpecializationSpecialization.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPClassTemplatePartialSpecializationSpecialization.java index 724f7901936..3266fc09a5b 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPClassTemplatePartialSpecializationSpecialization.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPClassTemplatePartialSpecializationSpecialization.java @@ -91,9 +91,9 @@ public class CPPClassTemplatePartialSpecializationSpecialization extends CPPClas ICPPTemplateArgument[] args = ((ICPPClassTemplatePartialSpecialization) getSpecializedBinding()).getTemplateArguments(); final IBinding owner = getOwner(); if (owner instanceof ICPPClassSpecialization) { - return CPPTemplates.instantiateArguments(args, getTemplateParameterMap(), (ICPPClassSpecialization) owner); + return CPPTemplates.instantiateArguments(args, getTemplateParameterMap(), -1, (ICPPClassSpecialization) owner); } - return CPPTemplates.instantiateArguments(args, getTemplateParameterMap(), null); + return CPPTemplates.instantiateArguments(args, getTemplateParameterMap(), -1, null); } public void addPartialSpecialization(ICPPClassTemplatePartialSpecialization spec) { diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPClassTemplateSpecialization.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPClassTemplateSpecialization.java index 199f438deae..332a096e0bd 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPClassTemplateSpecialization.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPClassTemplateSpecialization.java @@ -53,6 +53,8 @@ public class CPPClassTemplateSpecialization extends CPPClassSpecialization } public ICPPTemplateParameter[] getTemplateParameters() throws DOMException { + // mstodo if we specialize the template parameters (because of its default values), it will + // be less error prone to use the defaults. ICPPClassTemplate template = (ICPPClassTemplate) getSpecializedBinding(); return template.getTemplateParameters(); } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPFunctionSpecialization.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPFunctionSpecialization.java index de58803f982..2e98961df15 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPFunctionSpecialization.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPFunctionSpecialization.java @@ -28,6 +28,7 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFunctionDeclarator; 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.ICPPParameter; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPParameterPackType; import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateParameterMap; import org.eclipse.cdt.core.index.IIndexBinding; import org.eclipse.cdt.internal.core.dom.parser.ASTInternal; @@ -288,8 +289,24 @@ public class CPPFunctionSpecialization extends CPPSpecialization implements ICPP IType[] types = function.getExceptionSpecification(); if (types != null) { IType[] specializedTypeList = new IType[types.length]; - for (int i=0; i= 0) + return args[packOffset]; + } + return null; + } + + /** + * Returns the argument at the given position + */ + public boolean putPackElement(Integer paramID, int packOffset, ICPPTemplateArgument arg, int packSize) { + ICPPTemplateArgument[] args; + final Object object = fMap.get(paramID); + if (object instanceof ICPPTemplateArgument[]) { + args = (ICPPTemplateArgument[]) object; + if (packSize != args.length) + return false; + } else if (object == null) { + args= new ICPPTemplateArgument[packSize]; + fMap.put(paramID, args); + } else { + return false; + } + args[packOffset]= arg; + return true; } /** * Puts all mappings from the supplied map into this map. */ public void putAll(ICPPTemplateParameterMap map) { - if (map instanceof CPPTemplateParameterMap) { final ObjectMap omap= ((CPPTemplateParameterMap) map).fMap; for (int i = 0; i < omap.size(); i++) { @@ -84,12 +159,35 @@ public class CPPTemplateParameterMap implements ICPPTemplateParameterMap { } } - public ICPPTemplateArgument[] values() { - ICPPTemplateArgument[] result= new ICPPTemplateArgument[fMap.size()]; - for (int i = 0; i < result.length; i++) { - result[i]= (ICPPTemplateArgument) fMap.getAt(i); + public boolean mergeToExplicit(CPPTemplateParameterMap deducedMap) { + Integer[] keys= deducedMap.getAllParameterPositions(); + for (Integer key : keys) { + Object explicit= fMap.get(key); + Object deduced= deducedMap.fMap.get(key); + if (explicit == null) { + if (deduced instanceof ICPPTemplateArgument[]) { + for (ICPPTemplateArgument arg : (ICPPTemplateArgument[]) deduced) { + if (arg == null) + return false; + } + } + fMap.put(key, deduced); + } else if (explicit instanceof ICPPTemplateArgument[] && deduced instanceof ICPPTemplateArgument[]) { + ICPPTemplateArgument[] explicitPack= (ICPPTemplateArgument[]) explicit; + ICPPTemplateArgument[] deducedPack= (ICPPTemplateArgument[]) deduced; + if (deducedPack.length < explicitPack.length) + return false; + System.arraycopy(explicitPack, 0, deducedPack, 0, explicitPack.length); + for (ICPPTemplateArgument arg : deducedPack) { + if (arg == null) + return false; + } + fMap.put(key, deducedPack); + } else { + return false; + } } - return result; + return true; } /** @@ -111,16 +209,27 @@ public class CPPTemplateParameterMap implements ICPPTemplateParameterMap { if (sb.length() > 1) { sb.append(", "); //$NON-NLS-1$ } - ICPPTemplateArgument value = (ICPPTemplateArgument) fMap.getAt(i); - sb.append('#'); - sb.append(key >> 16); - sb.append(','); - sb.append(key & 0xffff); - sb.append(": "); //$NON-NLS-1$ - sb.append(ASTTypeUtil.getArgumentString(value, true)); + + final Object obj = fMap.getAt(i); + if (obj instanceof ICPPTemplateArgument) { + appendArg(sb, key, (ICPPTemplateArgument) obj); + } else if (obj instanceof ICPPTemplateArgument[]) { + for (ICPPTemplateArgument arg : (ICPPTemplateArgument[]) obj) { + appendArg(sb, key, arg); + } + } } } sb.append("}"); //$NON-NLS-1$ return sb.toString(); } + + private void appendArg(StringBuilder sb, Integer key, ICPPTemplateArgument value) { + sb.append('#'); + sb.append(key >> 16); + sb.append(','); + sb.append(key & 0xffff); + sb.append(": "); //$NON-NLS-1$ + sb.append(ASTTypeUtil.getArgumentString(value, true)); + } } 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 28f111e42b8..7345e64f1d8 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 @@ -13,8 +13,6 @@ *******************************************************************************/ package org.eclipse.cdt.internal.core.dom.parser.cpp.semantics; -import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.*; - import java.util.ArrayList; import java.util.BitSet; import java.util.Collections; @@ -36,15 +34,12 @@ 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.IBinding; import org.eclipse.cdt.core.dom.ast.IEnumeration; import org.eclipse.cdt.core.dom.ast.IEnumerator; import org.eclipse.cdt.core.dom.ast.IFunction; import org.eclipse.cdt.core.dom.ast.IFunctionType; -import org.eclipse.cdt.core.dom.ast.IPointerType; import org.eclipse.cdt.core.dom.ast.IProblemBinding; -import org.eclipse.cdt.core.dom.ast.IQualifierType; import org.eclipse.cdt.core.dom.ast.IScope; import org.eclipse.cdt.core.dom.ast.IType; import org.eclipse.cdt.core.dom.ast.ITypedef; @@ -62,7 +57,6 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTemplateDeclaration; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTemplateId; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTemplateParameter; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTemplatedTypeTemplateParameter; -import org.eclipse.cdt.core.dom.ast.cpp.ICPPBase; import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassScope; import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassSpecialization; import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassTemplate; @@ -76,7 +70,6 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPFunctionType; import org.eclipse.cdt.core.dom.ast.cpp.ICPPMethod; import org.eclipse.cdt.core.dom.ast.cpp.ICPPParameterPackType; 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.ICPPScope; import org.eclipse.cdt.core.dom.ast.cpp.ICPPSpecialization; import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateArgument; @@ -123,7 +116,6 @@ 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; @@ -153,74 +145,82 @@ import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.Cost.Rank; * type instantiation. */ public class CPPTemplates { + private static final BitSet ALL_RVALUES = new BitSet(); + private static final int PACK_SIZE_DEFER = -1; + private static final int PACK_SIZE_FAIL = -2; + private static final int PACK_SIZE_NOT_FOUND = Integer.MAX_VALUE; /** * Instantiates a class template with the given arguments. May return null. */ - public static IBinding instantiate(ICPPClassTemplate template, ICPPTemplateArgument[] arguments, boolean isDef) { + public static IBinding instantiate(ICPPClassTemplate template, ICPPTemplateArgument[] args, boolean isDef) { try { - arguments= SemanticUtil.getSimplifiedArguments(arguments); + // Add default arguments, if necessary. + ICPPTemplateArgument[] arguments= SemanticUtil.getSimplifiedArguments(args); + arguments= addDefaultArguments(template, arguments); + if (arguments == null) + return createProblem(template, IProblemBinding.SEMANTIC_INVALID_TEMPLATE_ARGUMENTS); + if (template instanceof ICPPTemplateTemplateParameter || hasDependentArgument(arguments)) { return deferredInstance(template, arguments); } if (template instanceof ICPPClassTemplatePartialSpecialization) { - return instantiatePartialSpecialization((ICPPClassTemplatePartialSpecialization) template, arguments, isDef); + return instantiatePartialSpecialization((ICPPClassTemplatePartialSpecialization) template, arguments, isDef, null); } - // check whether we need to use default arguments + final ICPPTemplateParameter[] parameters= template.getTemplateParameters(); final int numArgs = arguments.length; final int numParams= parameters.length; - if (numParams == 0 || numParams < numArgs) - return createProblem(template, IProblemBinding.SEMANTIC_INVALID_TEMPLATE_ARGUMENTS); + final int length= Math.max(numArgs, numParams); - ICPPTemplateArgument[] completeArgs= new ICPPTemplateArgument[numParams]; CPPTemplateParameterMap map= new CPPTemplateParameterMap(numParams); - boolean hasDependentDefaultArg= false; - for (int i = 0; i < numParams; i++) { - ICPPTemplateArgument arg; - ICPPTemplateParameter param= parameters[i]; - if (i < numArgs) { - arg= arguments[i]; - } else { - ICPPTemplateArgument defaultArg= param.getDefaultValue(); - if (defaultArg == null) { - if (template instanceof ICPPInternalClassTemplate) { - defaultArg= ((ICPPInternalClassTemplate) template).getDefaultArgFromIndex(i); - } - if (defaultArg == null) - return createProblem(template, IProblemBinding.SEMANTIC_INVALID_TEMPLATE_ARGUMENTS); - } - arg= instantiateArgument(defaultArg, map, null); - arg= SemanticUtil.getSimplifiedArgument(arg); - hasDependentDefaultArg |= isDependentArgument(arg); - } - - if (!hasDependentDefaultArg) { - arg= CPPTemplates.matchTemplateParameterAndArgument(param, arg, map); - if (arg == null) + boolean isPack= false; + ICPPTemplateParameter param= null; + for (int i = 0; i < length; i++) { + if (!isPack || param == null) { + if (i < numParams) { + param= parameters[i]; + isPack= param.isParameterPack(); + } else { return createProblem(template, IProblemBinding.SEMANTIC_INVALID_TEMPLATE_ARGUMENTS); + } } - - map.put(param, arg); - completeArgs[i]= arg; + if (i < numArgs) { + ICPPTemplateArgument arg= arguments[i]; + ICPPTemplateArgument newArg = CPPTemplates.matchTemplateParameterAndArgument(param, arg, map); + if (newArg == null) + return createProblem(template, IProblemBinding.SEMANTIC_INVALID_TEMPLATE_ARGUMENTS); + if (newArg != arg) { + if (arguments == args) { + arguments= args.clone(); + } + arguments[i]= newArg; + } + if (!isPack) { + map.put(param, newArg); + } + } else { + // Parameter pack with empty arguments. + assert isPack; + } + } + + if (isPack) { + int packOffset= numParams-1; + int packSize= numArgs - packOffset; + ICPPTemplateArgument[] pack= new ICPPTemplateArgument[packSize]; + System.arraycopy(arguments, packOffset, pack, 0, packSize); + map.put(param, pack); } - if (hasDependentDefaultArg) - return deferredInstance(template, completeArgs); - - - ICPPTemplateDefinition tdef = CPPTemplates.selectSpecialization(template, completeArgs); - if (tdef == null || tdef instanceof IProblemBinding) - return tdef; - - if (tdef instanceof ICPPClassTemplatePartialSpecialization) { - return instantiatePartialSpecialization((ICPPClassTemplatePartialSpecialization) tdef, completeArgs, isDef); - } - - return instantiatePrimaryTemplate(template, completeArgs, map, isDef); + IBinding result= CPPTemplates.selectSpecialization(template, arguments, isDef); + if (result != null) + return result; + + return instantiatePrimaryTemplate(template, arguments, map, isDef); } catch (DOMException e) { return e.getProblem(); } @@ -277,20 +277,17 @@ public class CPPTemplates { /** * Instantiates a partial class template specialization. */ - private static IBinding instantiatePartialSpecialization(ICPPClassTemplatePartialSpecialization partialSpec, ICPPTemplateArgument[] args, boolean isDef) throws DOMException { + private static IBinding instantiatePartialSpecialization( + ICPPClassTemplatePartialSpecialization partialSpec, ICPPTemplateArgument[] args, boolean isDef, + CPPTemplateParameterMap tpMap) throws DOMException { ICPPTemplateInstance instance= getInstance(partialSpec, args, isDef); if (instance != null) return instance; - CPPTemplateParameterMap tpMap= new CPPTemplateParameterMap(args.length); - if (!CPPTemplates.deduceTemplateParameterMap(partialSpec.getTemplateArguments(), args, tpMap)) - return null; - - ICPPTemplateParameter[] params= partialSpec.getTemplateParameters(); - int numParams = params.length; - for (int i = 0; i < numParams; i++) { - final ICPPTemplateParameter param = params[i]; - if (tpMap.getArgument(param) == null) + if (tpMap == null) { + tpMap = new CPPTemplateParameterMap(args.length); + if (!TemplateArgumentDeduction.fromTemplateArguments(partialSpec.getTemplateParameters(), + partialSpec.getTemplateArguments(), args, tpMap)) return null; } @@ -318,23 +315,13 @@ public class CPPTemplates { return instance; } - private static IBinding instantiateFunctionTemplate(ICPPFunctionTemplate template, ICPPTemplateArgument[] arguments) - throws DOMException { + private static IBinding instantiateFunctionTemplate(ICPPFunctionTemplate template, + ICPPTemplateArgument[] arguments, CPPTemplateParameterMap map) throws DOMException { ICPPTemplateInstance instance= getInstance(template, arguments, false); if (instance != null) { return instance; } - final int length = arguments.length; - ICPPTemplateParameter[] parameters= template.getTemplateParameters(); - if (parameters.length != length) - return null; - - CPPTemplateParameterMap map = new CPPTemplateParameterMap(length); - for (int i = 0; i < length; i++) { - map.put(parameters[i], arguments[i]); - } - IBinding owner= template.getOwner(); instance = CPPTemplates.createInstance(owner, template, map, arguments); addInstance(template, arguments, instance); @@ -344,7 +331,8 @@ public class CPPTemplates { /** * Obtains a cached instance from the template. */ - private static ICPPTemplateInstance getInstance(ICPPTemplateDefinition template, ICPPTemplateArgument[] args, boolean forDefinition) { + private static ICPPTemplateInstance getInstance(ICPPTemplateDefinition template, + ICPPTemplateArgument[] args, boolean forDefinition) { if (template instanceof ICPPInstanceCache) { ICPPTemplateInstance result = ((ICPPInstanceCache) template).getInstance(args); if (forDefinition && result instanceof IIndexBinding) @@ -373,6 +361,84 @@ public class CPPTemplates { return instance; } + private static ICPPTemplateArgument[] addDefaultArguments(ICPPClassTemplate template, + ICPPTemplateArgument[] arguments) throws DOMException { + if (template instanceof ICPPClassTemplatePartialSpecialization) + return arguments; + + boolean havePackExpansion= false; + for (int i = 0; i < arguments.length; i++) { + ICPPTemplateArgument arg = arguments[i]; + if (arg.isPackExpansion()) { + if (i != arguments.length-1) { + return arguments; + } + havePackExpansion= true; + } + } + + ICPPTemplateParameter[] tpars = template.getTemplateParameters(); + int tparCount = tpars.length; + final int argCount = arguments.length; + + if (tparCount == argCount) + return arguments; + + if (tparCount == 0) + return null; + + // More arguments allowed if we have a parameter pack. + if (tparCount < argCount) { + if (tpars[tparCount-1].isParameterPack()) + return arguments; + + if (havePackExpansion && tparCount+1 == argCount) + return arguments; + return null; + } + + // Fewer arguments are allowed with a pack expansion + if (havePackExpansion) + return arguments; + + // Fewer arguments are allowed with default arguments + if (tpars[tparCount-1].isParameterPack()) + tparCount--; + + if (tparCount == argCount) + return arguments; + + ICPPTemplateArgument[] completeArgs= new ICPPTemplateArgument[tparCount]; + CPPTemplateParameterMap map= new CPPTemplateParameterMap(tparCount); + for (int i = 0; i < tparCount; i++) { + final ICPPTemplateParameter tpar = tpars[i]; + if (tpar.isParameterPack()) { + // Parameter pack must be last template parameter. + return null; + } + ICPPTemplateArgument arg; + if (i < argCount) { + arg= arguments[i]; + } else { + ICPPTemplateArgument defaultArg= tpar.getDefaultValue(); + if (defaultArg == null) { + if (template instanceof ICPPInternalClassTemplate) { + defaultArg= ((ICPPInternalClassTemplate) template).getDefaultArgFromIndex(i); + } + } + if (defaultArg == null) + return null; + arg= instantiateArgument(defaultArg, map, -1, null); + if (!isValidArgument(arg)) { + return null; + } + } + map.put(tpar, arg); + completeArgs[i]= arg; + } + return completeArgs; + } + /** * Instantiates the template for usage within its own body. May return null. */ @@ -636,73 +702,6 @@ public class CPPTemplates { parentOfName instanceof ICPPASTBaseSpecifier; } - /** - * Deduce arguments for a template function from the template id + the template function parameters. - * 14.8.2.1 - */ - static private ICPPTemplateArgument[] deduceTemplateFunctionArguments(ICPPFunctionTemplate template, - ICPPTemplateArgument[] tmplArgs, IType[] fnArgs, BitSet argIsLValue, CPPTemplateParameterMap map) throws DOMException { - final ICPPTemplateParameter[] tmplParams = template.getTemplateParameters(); - final int length = tmplParams.length; - if (tmplArgs.length > length) - return null; - - ICPPTemplateArgument[] result = new ICPPTemplateArgument[length]; - tmplArgs= SemanticUtil.getSimplifiedArguments(tmplArgs); - for (int i = 0; i < tmplArgs.length; i++) { - ICPPTemplateArgument tmplArg= tmplArgs[i]; - final ICPPTemplateParameter tmplParam= tmplParams[i]; - tmplArg= matchTemplateParameterAndArgument(tmplParam, tmplArg, map); - if (tmplArg == null) - return null; - - tmplArg= SemanticUtil.getSimplifiedArgument(tmplArg); - map.put(tmplParam, tmplArg); - result[i]= tmplArg; - } - - if (!deduceTemplateParameterMapFromFunctionParameters(template, fnArgs, argIsLValue, map, false)) - return null; - - for (int i = 0; i < length; i++) { - if (result[i] == null) { - ICPPTemplateArgument deducedArg= map.getArgument(tmplParams[i]); - if (deducedArg == null) - return null; - result[i]= deducedArg; - } - } - return result; - } - - /** - * Deduce arguments for a user defined conversion template - * 14.8.2.3 - */ - static private ICPPTemplateArgument[] deduceTemplateConversionArguments(ICPPFunctionTemplate template, - IType conversionType, CPPTemplateParameterMap map) throws DOMException { - final ICPPTemplateParameter[] tmplParams = template.getTemplateParameters(); - final int length = tmplParams.length; - - ICPPTemplateArgument[] result = new ICPPTemplateArgument[length]; - IType a= SemanticUtil.getSimplifiedType(conversionType); - IType p= template.getType().getReturnType(); - p= getArgumentTypeForDeduction(p, a instanceof ICPPReferenceType); - a= SemanticUtil.getNestedType(a, SemanticUtil.REF | SemanticUtil.TDEF); - if (!deduceTemplateParameterMap(p, a, map)) { - return null; - } - - for (int i = 0; i < length; i++) { - if (result[i] == null) { - ICPPTemplateArgument deducedArg= map.getArgument(tmplParams[i]); - if (deducedArg == null) - return null; - result[i]= deducedArg; - } - } - return result; - } public static ICPPTemplateInstance createInstance(IBinding owner, ICPPTemplateDefinition template, CPPTemplateParameterMap tpMap, ICPPTemplateArgument[] args) { @@ -766,7 +765,7 @@ public class CPPTemplates { return spec; } - public static IValue instantiateValue(IValue value, ICPPTemplateParameterMap tpMap, ICPPClassSpecialization within, int maxdepth) { + public static IValue instantiateValue(IValue value, ICPPTemplateParameterMap tpMap, int packOffset, ICPPClassSpecialization within, int maxdepth) { if (value == null) return null; IBinding[] unknowns= value.getUnknownBindings(); @@ -777,7 +776,7 @@ public class CPPTemplates { IBinding resolved= unknown; if (unknown instanceof ICPPUnknownBinding) { try { - resolved= resolveUnknown((ICPPUnknownBinding) unknown, tpMap, within); + resolved= resolveUnknown((ICPPUnknownBinding) unknown, tpMap, packOffset, within); } catch (DOMException e) { return Value.UNKNOWN; } @@ -792,21 +791,249 @@ public class CPPTemplates { } } - if (resolvedUnknowns != null) - return Value.reevaluate(value, resolvedUnknowns, tpMap, maxdepth); + if (resolvedUnknowns != null) + return Value.reevaluate(value, packOffset, resolvedUnknowns, tpMap, maxdepth); if (Value.referencesTemplateParameter(value)) - return Value.reevaluate(value, unknowns, tpMap, maxdepth); + return Value.reevaluate(value, packOffset, unknowns, tpMap, maxdepth); return value; } + public static boolean containsParameterPack(IType type) { + return determinePackSize(type, CPPTemplateParameterMap.EMPTY) == PACK_SIZE_DEFER; + } + + private static int determinePackSize(IType type, ICPPTemplateParameterMap tpMap) { + try { + if (type instanceof ICPPFunctionType) { + final ICPPFunctionType ft = (ICPPFunctionType) type; + final IType rt = ft.getReturnType(); + int r = determinePackSize(rt, tpMap); + if (r < 0) + return r; + IType[] ps = ft.getParameterTypes(); + for (IType pt : ps) { + r= combine(r, determinePackSize(pt, tpMap)); + if (r < 0) + return r; + } + return r; + } + + if (type instanceof ICPPTemplateParameter) { + final ICPPTemplateParameter tpar = (ICPPTemplateParameter) type; + if (tpar.isParameterPack()) { + ICPPTemplateArgument[] args= tpMap.getPackExpansion(tpar); + if (args != null) + return args.length; + return PACK_SIZE_DEFER; + } + return PACK_SIZE_NOT_FOUND; + } + + int r= PACK_SIZE_NOT_FOUND; + if (type instanceof ICPPUnknownBinding) { + if (type instanceof ICPPDeferredClassInstance) { + ICPPDeferredClassInstance dcl= (ICPPDeferredClassInstance) type; + ICPPTemplateArgument[] args = dcl.getTemplateArguments(); + for (ICPPTemplateArgument arg : args) { + r= combine(r, determinePackSize(arg, tpMap)); + if (r < 0) + return r; + } + } + IBinding binding= ((ICPPUnknownBinding) type).getOwner(); + if (binding instanceof IType) + r= combine(r, determinePackSize((IType) binding, tpMap)); + + return r; + } + + if (type instanceof ICPPParameterPackType) + return PACK_SIZE_NOT_FOUND; + + if (type instanceof IArrayType) { + IArrayType at= (IArrayType) type; + IValue asize= at.getSize(); + r= determinePackSize(asize, tpMap); + if (r < 0) + return r; + } + + if (type instanceof ITypeContainer) { + final ITypeContainer typeContainer = (ITypeContainer) type; + r= combine(r, determinePackSize(typeContainer.getType(), tpMap)); + } + return r; + } catch (DOMException e) { + return PACK_SIZE_FAIL; + } + } + + private static int combine(int ps1, int ps2) { + if (ps1 < 0 || ps2 == PACK_SIZE_NOT_FOUND) + return ps1; + if (ps2 < 0 || ps1 == PACK_SIZE_NOT_FOUND) + return ps2; + if (ps1 != ps2) + return PACK_SIZE_FAIL; + return ps1; + } + + private static int determinePackSize(IValue value, ICPPTemplateParameterMap tpMap) { + int r= PACK_SIZE_NOT_FOUND; + IBinding[] unknown= value.getUnknownBindings(); + for (IBinding binding : unknown) { + if (binding instanceof IType) { + r= combine(r, determinePackSize((IType) binding, tpMap)); + if (r < 0) + return r; + } + } + int[] tpars= Value.getParameterPackReferences(value); + for (int parID : tpars) { + ICPPTemplateArgument[] args= tpMap.getPackExpansion(parID); + if (args != null) { + r= combine(r, args.length); + if (r < 0) + return r; + } + return PACK_SIZE_DEFER; + } + return r; + } + + private static int determinePackSize(ICPPTemplateArgument arg, ICPPTemplateParameterMap tpMap) { + if (arg.isTypeValue()) + return determinePackSize(arg.getTypeValue(), tpMap); + return determinePackSize(arg.getNonTypeValue(), tpMap); + } + + /** + * Instantiates types contained in an array. + * @param types an array of types + * @param tpMap template argument map + * @return an array containing instantiated types. + */ + public static IType[] instantiateTypes(IType[] types, ICPPTemplateParameterMap tpMap, int packOffset, ICPPClassSpecialization within) { + // Don't create a new array until it's really needed. + IType[] result = types; + for (int i = 0; i < types.length; i++) { + IType origType = types[i]; + IType newType; + if (origType instanceof ICPPParameterPackType) { + if (i != types.length-1) { + newType= new ProblemBinding(null, IProblemBinding.SEMANTIC_INVALID_TYPE); + } else { + origType= ((ICPPParameterPackType) origType).getType(); + int packSize= determinePackSize(origType, tpMap); + if (packSize == PACK_SIZE_FAIL || packSize == PACK_SIZE_NOT_FOUND) { + newType= new ProblemBinding(null, IProblemBinding.SEMANTIC_INVALID_TYPE); + } else if (packSize == PACK_SIZE_DEFER) { + newType= origType; + } else { + IType[] packResult= new IType[types.length+packSize-1]; + System.arraycopy(result, 0, packResult, 0, types.length-1); + for(int j=0; j 0) { + System.arraycopy(types, 0, result, 0, i); + } + result[i]= newType; + } + } + return result; + } + + /** + * Instantiates arguments contained in an array. + */ + public static ICPPTemplateArgument[] instantiateArguments(ICPPTemplateArgument[] args, + ICPPTemplateParameterMap tpMap, int packOffset, ICPPClassSpecialization within) + throws DOMException { + // Don't create a new array until it's really needed. + ICPPTemplateArgument[] result = args; + int resultShift= 0; + for (int i = 0; i < args.length; i++) { + ICPPTemplateArgument origArg = args[i]; + ICPPTemplateArgument newArg; + if (origArg.isPackExpansion()) { + origArg= origArg.getExpansionPattern(); + int packSize= determinePackSize(origArg, tpMap); + if (packSize == PACK_SIZE_FAIL || packSize == PACK_SIZE_NOT_FOUND) { + throw new DOMException(new ProblemBinding(null, IProblemBinding.SEMANTIC_INVALID_TEMPLATE_ARGUMENTS)); + } else if (packSize == PACK_SIZE_DEFER) { + newArg= origArg; + } else { + final int shift = packSize-1; + ICPPTemplateArgument[] newResult= new ICPPTemplateArgument[args.length + resultShift + shift]; + System.arraycopy(result, 0, newResult, 0, i+resultShift); + for(int j=0; j 0) { + System.arraycopy(args, 0, result, 0, i); + } + result[i]= newArg; + } + } + return result; + } + + /** + * Instantiates an argument + */ + static ICPPTemplateArgument instantiateArgument(ICPPTemplateArgument arg, + ICPPTemplateParameterMap tpMap, int packOffset, ICPPClassSpecialization within) { + if (arg == null) + return null; + if (arg.isNonTypeValue()) { + final IValue origValue= arg.getNonTypeValue(); + final IType origType= arg.getTypeOfNonTypeValue(); + final IValue instValue= instantiateValue(origValue, tpMap, packOffset, within, Value.MAX_RECURSION_DEPTH); + final IType instType= instantiateType(origType, tpMap, packOffset, within); + if (origType == instType && origValue == instValue) + return arg; + return new CPPTemplateArgument(instValue, instType); + } + + final IType orig= arg.getTypeValue(); + final IType inst= instantiateType(orig, tpMap, packOffset, within); + if (orig == inst) + return arg; + return new CPPTemplateArgument(inst); + } + /** * This method propagates the specialization of a member to the types used by the member. * @param type a type to instantiate. * @param tpMap a mapping between template parameters and the corresponding arguments. */ - public static IType instantiateType(IType type, ICPPTemplateParameterMap tpMap, ICPPClassSpecialization within) { + public static IType instantiateType(IType type, ICPPTemplateParameterMap tpMap, int packOffset, ICPPClassSpecialization within) { try { if (tpMap == null) return type; @@ -816,9 +1043,9 @@ public class CPPTemplates { IType ret = null; IType[] params = null; final IType r = ft.getReturnType(); - ret = instantiateType(r, tpMap, within); + ret = instantiateType(r, tpMap, packOffset, within); IType[] ps = ft.getParameterTypes(); - params = instantiateTypes(ps, tpMap, within); + params = instantiateTypes(ps, tpMap, packOffset, within); if (ret == r && params == ps) { return type; } @@ -826,7 +1053,22 @@ public class CPPTemplates { } if (type instanceof ICPPTemplateParameter) { - ICPPTemplateArgument arg= tpMap.getArgument((ICPPTemplateParameter) type); + final ICPPTemplateParameter tpar = (ICPPTemplateParameter) type; + ICPPTemplateArgument arg= null; + if (tpar.isParameterPack()) { + if (packOffset >= 0) { + ICPPTemplateArgument[] args = tpMap.getPackExpansion(tpar); + if (args != null) { + if (packOffset >= args.length) { + return new ProblemBinding(null, IProblemBinding.SEMANTIC_INVALID_TYPE); + } + arg= args[packOffset]; + } + } + } else { + arg= tpMap.getArgument(tpar); + } + if (arg != null) { IType t= arg.getTypeValue(); if (t != null) @@ -836,7 +1078,7 @@ public class CPPTemplates { } if (type instanceof ICPPUnknownBinding) { - IBinding binding= resolveUnknown((ICPPUnknownBinding) type, tpMap, within); + IBinding binding= resolveUnknown((ICPPUnknownBinding) type, tpMap, packOffset, within); if (binding instanceof IType) return (IType) binding; @@ -852,7 +1094,7 @@ public class CPPTemplates { IBinding typeAsBinding= (IBinding) type; IBinding typeOwner= typeAsBinding.getOwner(); if (typeOwner instanceof IType) { - IType newOwner= instantiateType((IType) typeOwner, tpMap, within); + IType newOwner= instantiateType((IType) typeOwner, tpMap, packOffset, within); if (newOwner != typeOwner && newOwner instanceof ICPPClassSpecialization) { return (IType) ((ICPPClassSpecialization) newOwner).specializeMember(typeAsBinding); } @@ -863,11 +1105,11 @@ public class CPPTemplates { if (type instanceof ITypeContainer) { final ITypeContainer typeContainer = (ITypeContainer) type; IType nestedType = typeContainer.getType(); - IType newNestedType = instantiateType(nestedType, tpMap, within); + IType newNestedType = instantiateType(nestedType, tpMap, packOffset, within); if (typeContainer instanceof ICPPPointerToMemberType) { ICPPPointerToMemberType ptm = (ICPPPointerToMemberType) typeContainer; IType memberOfClass = ptm.getMemberOfClass(); - IType newMemberOfClass = instantiateType(memberOfClass, tpMap, within); + IType newMemberOfClass = instantiateType(memberOfClass, tpMap, packOffset, within); if (newNestedType != nestedType || newMemberOfClass != memberOfClass) { if (newMemberOfClass instanceof ICPPClassType) { return new CPPPointerToMemberType(newNestedType, newMemberOfClass, @@ -879,7 +1121,7 @@ public class CPPTemplates { IArrayType at= (IArrayType) typeContainer; IValue asize= at.getSize(); if (asize != null) { - IValue newSize= instantiateValue(asize, tpMap, within, Value.MAX_RECURSION_DEPTH); + IValue newSize= instantiateValue(asize, tpMap, packOffset, within, Value.MAX_RECURSION_DEPTH); if (newSize != asize) { return new CPPArrayType(newNestedType, newSize); } @@ -897,73 +1139,6 @@ public class CPPTemplates { } } - /** - * Instantiates types contained in an array. - * @param types an array of types - * @param tpMap template argument map - * @return an array containing instantiated types. - */ - public static IType[] instantiateTypes(IType[] types, ICPPTemplateParameterMap tpMap, ICPPClassSpecialization within) { - // Don't create a new array until it's really needed. - IType[] result = types; - for (int i = 0; i < types.length; i++) { - IType type = CPPTemplates.instantiateType(types[i], tpMap, within); - if (result != types) { - result[i]= type; - } else if (type != types[i]) { - result = new IType[types.length]; - if (i > 0) { - System.arraycopy(types, 0, result, 0, i); - } - result[i]= type; - } - } - return result; - } - - /** - * Instantiates arguments contained in an array. - */ - public static ICPPTemplateArgument[] instantiateArguments(ICPPTemplateArgument[] types, ICPPTemplateParameterMap tpMap, ICPPClassSpecialization within) { - // Don't create a new array until it's really needed. - ICPPTemplateArgument[] result = types; - for (int i = 0; i < types.length; i++) { - ICPPTemplateArgument type = CPPTemplates.instantiateArgument(types[i], tpMap, within); - if (result != types) { - result[i]= type; - } else if (type != types[i]) { - result = new ICPPTemplateArgument[types.length]; - if (i > 0) { - System.arraycopy(types, 0, result, 0, i); - } - result[i]= type; - } - } - return result; - } - - /** - * Instantiates an argument - */ - private static ICPPTemplateArgument instantiateArgument(ICPPTemplateArgument arg, - ICPPTemplateParameterMap tpMap, ICPPClassSpecialization within) { - if (arg.isNonTypeValue()) { - final IValue origValue= arg.getNonTypeValue(); - final IType origType= arg.getTypeOfNonTypeValue(); - final IValue instValue= instantiateValue(origValue, tpMap, within, Value.MAX_RECURSION_DEPTH); - final IType instType= instantiateType(origType, tpMap, within); - if (origType == instType && origValue == instValue) - return arg; - return new CPPTemplateArgument(instValue, instType); - } - - final IType orig= arg.getTypeValue(); - final IType inst= instantiateType(orig, tpMap, within); - if (orig == inst) - return arg; - return new CPPTemplateArgument(inst); - } - /** * Checks whether a given name corresponds to a template declaration and returns the ast node for it. * This works for the name of a template-definition and also for a name needed to qualify a member @@ -1378,7 +1553,7 @@ public class CPPTemplates { } } - ICPPTemplateArgument[] templateArguments= null; + ICPPTemplateArgument[] tmplArgs= null; for (int i = 0; i < functions.length; i++) { IFunction func = functions[i]; if (func instanceof ICPPFunctionTemplate) { @@ -1386,16 +1561,16 @@ public class CPPTemplates { functions[i]= null; // extract template arguments and parameter types. - if (templateArguments == null || fnArgs == null) { - templateArguments = ICPPTemplateArgument.EMPTY_ARGUMENTS; + if (tmplArgs == null || fnArgs == null) { + tmplArgs = ICPPTemplateArgument.EMPTY_ARGUMENTS; try { if (containsDependentType(fnArgs)) { functions[i]= CPPUnknownFunction.createForSample(template); return; } if (name instanceof ICPPASTTemplateId && !(template instanceof ICPPConstructor)) { - templateArguments = createTemplateArgumentArray((ICPPASTTemplateId) name); - if (hasDependentArgument(templateArguments)) { + tmplArgs = createTemplateArgumentArray((ICPPASTTemplateId) name); + if (hasDependentArgument(tmplArgs)) { functions[i]= CPPUnknownFunction.createForSample(template); return; } @@ -1406,9 +1581,9 @@ public class CPPTemplates { } CPPTemplateParameterMap map= new CPPTemplateParameterMap(fnArgs.length); try { - ICPPTemplateArgument[] args= deduceTemplateFunctionArguments(template, templateArguments, fnArgs, argIsLValue, map); + ICPPTemplateArgument[] args= TemplateArgumentDeduction.deduceForFunctionCall(template, tmplArgs, fnArgs, argIsLValue, map); if (args != null) { - IBinding instance= instantiateFunctionTemplate(template, args); + IBinding instance= instantiateFunctionTemplate(template, args, map); if (instance instanceof IFunction) { functions[i]= (IFunction) instance; } @@ -1446,9 +1621,9 @@ public class CPPTemplates { } CPPTemplateParameterMap map= new CPPTemplateParameterMap(1); try { - ICPPTemplateArgument[] args= deduceTemplateConversionArguments(template, conversionType, map); + ICPPTemplateArgument[] args= TemplateArgumentDeduction.deduceForConversion(template, conversionType, map); if (args != null) { - IBinding instance= instantiateFunctionTemplate(template, args); + IBinding instance= instantiateFunctionTemplate(template, args, map); if (instance instanceof IFunction) { functions[i]= (IFunction) instance; } @@ -1460,348 +1635,6 @@ public class CPPTemplates { } } - /** - * Deduces the mapping for the template parameters from the function parameters, - * returns false if there is no mapping. - */ - private static boolean deduceTemplateParameterMapFromFunctionParameters(ICPPFunctionTemplate template, - IType[] fnArgs, BitSet argIsLValue, CPPTemplateParameterMap map, boolean checkExactMatch) throws DOMException { - try { - IType[] fnPars = template.getType().getParameterTypes(); - if (fnPars.length == 0) - return true; - - int len= Math.min(fnPars.length, fnArgs.length); - IType[] instPars= new IType[len]; - for (int j= 0; j < len; j++) { - IType par= fnPars[j]; - IType instPar= instantiateType(par, map, null); - if (!isValidType(instPar)) - return false; - instPars[j]= instPar; - } - - for (int j= 0; j < len; j++) { - IType par= instPars[j]; - boolean isDependentPar= isDependentType(par); - if (checkExactMatch || isDependentPar) { - boolean isReferenceTypeParameter= false; - IType arg = fnArgs[j]; - par= SemanticUtil.getNestedType(par, SemanticUtil.TDEF); // adjustParameterType preserves typedefs - // 14.8.2.1-2 - if (par instanceof ICPPReferenceType) { - // If P is an rvalue reference to a cv-unqualified template parameter and the argument is an - // lvalue, the type A& “lvalue reference to A” is used in place of A for type deduction. - isReferenceTypeParameter= true; - final ICPPReferenceType refPar = (ICPPReferenceType) par; - if (refPar.isRValueReference() && refPar.getType() instanceof ICPPTemplateParameter && argIsLValue.get(j)) { - arg= new CPPReferenceType(getSimplifiedType(arg), false); - } else { - arg= getArgumentTypeForDeduction(arg, true); - } - par= SemanticUtil.getNestedType(par, SemanticUtil.REF | SemanticUtil.TDEF); - } else { - arg= getArgumentTypeForDeduction(arg, false); - } - - if (!checkExactMatch) { - // 14.8.2.1-3 - 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 { - 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 (isDependentPar && !deduceTemplateParameterMap(par, arg, map)) { - return false; - } - if (checkExactMatch) { - IType instantiated= instantiateType(par, map, null); - if (!instantiated.isSameType(arg)) - return false; - } - } - } - return true; - } catch (DOMException e) { - } - return false; - } - - /** - * Deduces the template parameter mapping from pairs of template arguments. - */ - public static boolean deduceTemplateParameterMap(final ICPPTemplateArgument[] p, final ICPPTemplateArgument[] a, CPPTemplateParameterMap map) throws DOMException { - final int len= a.length; - if (p == null || p.length != len) { - return false; - } - for (int j=0; j= 0) { - ICPPTemplateArgument old= map.getArgument(parPos); - if (old == null) { - map.put(parPos, a); - return true; - } - return old.isSameValue(a); - } - - IValue sval= a.getNonTypeValue(); - return tval.equals(sval); - } - - return deduceTemplateParameterMap(p.getTypeValue(), a.getTypeValue(), map); - } - - /** - * 14.8.2.1-2 - * if P is not a reference type - * - If A is an array type, the pointer type produced by the array-to-pointer conversion is used instead - * - If A is a function type, the pointer type produced by the function-to-pointer conversion is used instead - * - If A is a cv-qualified type, the top level cv-qualifiers are ignored for type deduction - * - * Also 14.8.2.3-2 where the same logics is used in reverse. - */ - static private IType getArgumentTypeForDeduction(IType type, boolean parameterIsAReferenceType) { - type = SemanticUtil.getSimplifiedType(type); - if (type instanceof ICPPReferenceType) { - type = ((ICPPReferenceType) type).getType(); - } - IType result = type; - if (!parameterIsAReferenceType) { - if (type instanceof IArrayType) { - result = new CPPPointerType(((IArrayType) type).getType()); - } else if (type instanceof IFunctionType) { - result = new CPPPointerType(type); - } else { - result = SemanticUtil.getNestedType(type, TDEF | ALLCVQ ); - } - } - return result; - } - - private static boolean deduceTemplateParameterMap(IType p, IType a, CPPTemplateParameterMap map) throws DOMException { - while (p != null) { - while (a instanceof ITypedef) - a = ((ITypedef) a).getType(); - if (p instanceof IBasicType) { - return p.isSameType(a); - } else if (p instanceof ICPPPointerToMemberType) { - if (!(a instanceof ICPPPointerToMemberType)) - return false; - if (!deduceTemplateParameterMap(((ICPPPointerToMemberType) p).getMemberOfClass(), ((ICPPPointerToMemberType) a).getMemberOfClass(), - map)) { - return false; - } - p = ((ICPPPointerToMemberType) p).getType(); - a = ((ICPPPointerToMemberType) a).getType(); - } else if (p instanceof IPointerType) { - if (!(a instanceof IPointerType)) { - return false; - } - p = ((IPointerType) p).getType(); - a = ((IPointerType) a).getType(); - } else if (p instanceof ICPPReferenceType) { - if (!(a instanceof ICPPReferenceType)) { - return false; - } - p = ((ICPPReferenceType) p).getType(); - a = ((ICPPReferenceType) a).getType(); - } else if (p instanceof IArrayType) { - if (!(a instanceof IArrayType)) { - return false; - } - IArrayType aa= (IArrayType) a; - IArrayType pa= (IArrayType) p; - IValue as= aa.getSize(); - IValue ps= pa.getSize(); - if (as != ps) { - if (as == null || ps == null) - return false; - - int parPos= Value.isTemplateParameter(ps); - if (parPos >= 0) { - ICPPTemplateArgument old= map.getArgument(parPos); - if (old == null) { - map.put(parPos, new CPPTemplateArgument(ps, new CPPBasicType(Kind.eInt, 0))); - } else if (!ps.equals(old.getNonTypeValue())) { - return false; - } - } else if (!ps.equals(as)) { - return false; - } - } - p = pa.getType(); - a = aa.getType(); - } else if (p instanceof IQualifierType) { - IType uqp = SemanticUtil.getNestedType(p, ALLCVQ); - IType uqa = SemanticUtil.getNestedType(a, ALLCVQ); - if (uqp instanceof ICPPTemplateParameter) { - CVQualifier remaining= SemanticUtil.getCVQualifier(a).remove(SemanticUtil.getCVQualifier(p)); - if (remaining != CVQualifier._) { - uqa= SemanticUtil.addQualifiers(uqa, remaining.isConst(), remaining.isVolatile()); - } - } - a= uqa; - p= uqp; - } else if (p instanceof IFunctionType) { - if (!(a instanceof IFunctionType)) - return false; - if (!deduceTemplateParameterMap(((IFunctionType) p).getReturnType(), ((IFunctionType) a).getReturnType(), - map)) { - return false; - } - IType[] pParams = ((IFunctionType) p).getParameterTypes(); - IType[] aParams = ((IFunctionType) a).getParameterTypes(); - if (pParams.length != aParams.length) - return false; - for (int i = 0; i < pParams.length; i++) { - if (!deduceTemplateParameterMap(pParams[i], aParams[i], map)) - return false; - } - return true; - } else if (p instanceof ICPPTemplateParameter) { - ICPPTemplateArgument current= map.getArgument((ICPPTemplateParameter) p); - if (current != null) { - if (current.isNonTypeValue()) - return false; - return current.getTypeValue().isSameType(a); - } - if (a == null) - return false; - map.put((ICPPTemplateParameter)p, new CPPTemplateArgument(a)); - return true; - } else if (p instanceof ICPPTemplateInstance) { - if (!(a instanceof ICPPTemplateInstance)) - return false; - ICPPTemplateInstance pInst = (ICPPTemplateInstance) p; - ICPPTemplateInstance aInst = (ICPPTemplateInstance) a; - - ICPPClassTemplate pTemplate= getPrimaryTemplate(pInst); - ICPPClassTemplate aTemplate= getPrimaryTemplate(aInst); - if (pTemplate == null || aTemplate == null || !aTemplate.isSameType(pTemplate)) - return false; - - ICPPTemplateArgument[] pArgs = pInst.getTemplateArguments(); - ICPPTemplateArgument[] aArgs = aInst.getTemplateArguments(); - if (pArgs.length > aArgs.length) - return false; - - ICPPTemplateParameter[] tpars= null; - for (int i = 0; i < aArgs.length; i++) { - ICPPTemplateArgument pArg; - if (i < pArgs.length) { - pArg= pArgs[i]; - } else { - if (tpars == null) { - tpars= pTemplate.getTemplateParameters(); - if (tpars.length < aArgs.length) - return false; - } - pArg= tpars[i].getDefaultValue(); - if (pArg == null) - return false; - pArg= instantiateArgument(pArg, pInst.getTemplateParameterMap(), null); - } - if (!deduceTemplateParameterMap(pArg, aArgs[i], map)) - return false; - } - return true; - } else if (p instanceof ICPPUnknownBinding) { - return true; // An unknown type may match anything. - } else { - return p.isSameType(a); - } - } - - return false; - } - - /** - * 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) { - final ICPPTemplateInstance inst = (ICPPTemplateInstance) a; - ICPPClassTemplate tmpl= getPrimaryTemplate(inst); - if (pTemplate.isSameType(tmpl)) - return a; - } - if (maxdepth-- > 0) { - for (ICPPBase cppBase : a.getBases()) { - IBinding base= cppBase.getBaseClass(); - if (base instanceof ICPPClassType) { - final ICPPClassType inst= findBaseInstance((ICPPClassType) base, pTemplate, maxdepth); - if (inst != null) - return inst; - } - } - } - return null; - } - - private static ICPPClassTemplate getPrimaryTemplate(ICPPTemplateInstance inst) throws DOMException { - ICPPTemplateDefinition template= inst.getTemplateDefinition(); - if (template instanceof ICPPClassTemplatePartialSpecialization) { - return ((ICPPClassTemplatePartialSpecialization) template).getPrimaryClassTemplate(); - } else if (template instanceof ICPPClassTemplate) { - return (ICPPClassTemplate) template; - } - return null; - } - /** * Transforms a function template for use in partial ordering, as described in the * spec 14.5.5.2-3 @@ -1853,27 +1686,35 @@ public class CPPTemplates { // 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. - ICPPTemplateArgument[] transferArgs = createArgsForFunctionTemplateOrdering(f1.getTemplateParameters()); - IBinding transferredTemplate = instantiateFunctionTemplate(f1, transferArgs); + 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; - CPPTemplateParameterMap map= new CPPTemplateParameterMap(2); + map= new CPPTemplateParameterMap(2); final IType[] transferredParameterTypes = ((ICPPFunction) transferredTemplate).getType().getParameterTypes(); - if (!deduceTemplateParameterMapFromFunctionParameters(f2, transferredParameterTypes, new BitSet(), map, true)) + if (!TemplateArgumentDeduction.deduceFromFunctionArgs(f2, transferredParameterTypes, ALL_RVALUES, map, true)) return false; - final ICPPTemplateParameter[] tmplParams = f2.getTemplateParameters(); - for (ICPPTemplateParameter tmplParam : tmplParams) { - ICPPTemplateArgument deducedArg= map.getArgument(tmplParam); - if (deducedArg == null) + 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; + } } - return true; } - private static ICPPClassTemplatePartialSpecialization findPartialSpecialization(ICPPClassTemplate ct, ICPPTemplateArgument[] args) throws DOMException { + private static ICPPClassTemplatePartialSpecialization findPartialSpecialization(ICPPClassTemplate ct, + ICPPTemplateArgument[] args) throws DOMException { ICPPClassTemplatePartialSpecialization[] pspecs = ct.getPartialSpecializations(); if (pspecs != null && pspecs.length > 0) { final String argStr= ASTTypeUtil.getArgumentListString(args, true); @@ -1889,31 +1730,29 @@ public class CPPTemplates { return null; } - static public ICPPTemplateDefinition selectSpecialization(ICPPClassTemplate template, ICPPTemplateArgument[] args) - throws DOMException { + private static IBinding selectSpecialization(ICPPClassTemplate template, ICPPTemplateArgument[] args, + boolean isDef) throws DOMException { if (template == null) { return null; } - ICPPClassTemplatePartialSpecialization[] specializations = template.getPartialSpecializations(); - if (specializations == null) { - return template; - } - final int size= specializations.length; - if (size == 0) { - return template; + if (specializations == null || specializations.length == 0) { + return null; } ICPPClassTemplatePartialSpecialization bestMatch = null, spec = null; + CPPTemplateParameterMap bestMap= null; boolean bestMatchIsBest = true; - for (int i = 0; i < size; i++) { - spec = specializations[i]; - if (deduceTemplateParameterMap(spec.getTemplateArguments(), args, new CPPTemplateParameterMap(args.length))) { + for (ICPPClassTemplatePartialSpecialization specialization : specializations) { + spec = specialization; + final CPPTemplateParameterMap map = new CPPTemplateParameterMap(args.length); + if (TemplateArgumentDeduction.fromTemplateArguments(spec.getTemplateParameters(), spec.getTemplateArguments(), args, map)) { int compare = orderSpecializations(bestMatch, spec); if (compare == 0) { bestMatchIsBest = false; } else if (compare < 0) { bestMatch = spec; + bestMap= map; bestMatchIsBest = true; } } @@ -1926,9 +1765,9 @@ public class CPPTemplates { } if (bestMatch == null) - return template; + return null; - return bestMatch; + return instantiatePartialSpecialization(bestMatch, args, isDef, bestMap); } /** @@ -1981,33 +1820,32 @@ public class CPPTemplates { for (int i = 0; i < tpars1.length; i++) { transferMap.put(tpars1[i], helperArgs[i]); } - final ICPPTemplateArgument[] transferredArgs1 = instantiateArguments(targs1, transferMap, null); + final ICPPTemplateArgument[] transferredArgs1 = instantiateArguments(targs1, transferMap, -1, null); // deduce arguments for specialization 2 final CPPTemplateParameterMap deductionMap= new CPPTemplateParameterMap(2); - if (!deduceTemplateParameterMap(targs2, transferredArgs1, deductionMap)) + if (!TemplateArgumentDeduction.fromTemplateArguments(tpars2, targs2, transferredArgs1, deductionMap)) return false; - for (ICPPTemplateParameter tmplParam : tpars2) { - ICPPTemplateArgument deducedArg= deductionMap.getArgument(tmplParam); - if (deducedArg == null) - return false; - } // compare for (int i = 0; i < targs2.length; i++) { - ICPPTemplateArgument transferredArg2= instantiateArgument(targs2[i], deductionMap, null); + ICPPTemplateArgument transferredArg2= instantiateArgument(targs2[i], deductionMap, -1, null); if (!transferredArg2.isSameValue(transferredArgs1[i])) return false; } return true; } - static private boolean isValidType(IType t) { + static boolean isValidType(IType t) { while (t instanceof ITypeContainer) { t = ((ITypeContainer) t).getType(); } return !(t instanceof IProblemBinding); } + + static boolean isValidArgument(ICPPTemplateArgument arg) { + return arg != null && isValidType(arg.isTypeValue() ? arg.getTypeValue() : arg.getTypeOfNonTypeValue()); + } static protected ICPPTemplateArgument matchTemplateParameterAndArgument(ICPPTemplateParameter param, ICPPTemplateArgument arg, CPPTemplateParameterMap map) { @@ -2031,32 +1869,12 @@ public class CPPTemplates { try { pParams = ((ICPPTemplateTemplateParameter) param).getTemplateParameters(); aParams = ((ICPPTemplateDefinition) t).getTemplateParameters(); + if (!compareTemplateParameters(pParams, aParams)) + return null; } catch (DOMException e) { return null; } - int size = pParams.length; - if (aParams.length != size) { - return null; - } - - for (int i = 0; i < size; i++) { - final ICPPTemplateParameter pParam = pParams[i]; - final ICPPTemplateParameter aParam = aParams[i]; - boolean pb= pParam instanceof ICPPTemplateTypeParameter; - boolean ab= aParam instanceof ICPPTemplateTypeParameter; - if (pb != ab) - return null; - if (!pb) { - pb= pParam instanceof ICPPTemplateNonTypeParameter; - ab= aParam instanceof ICPPTemplateNonTypeParameter; - if (pb != ab) - return null; - assert pb || pParam instanceof ICPPTemplateTemplateParameter; // no other choice left - assert ab || aParam instanceof ICPPTemplateTemplateParameter; // no other choice left - } - } - return arg; } @@ -2067,7 +1885,7 @@ public class CPPTemplates { try { IType pType = ((ICPPTemplateNonTypeParameter) param).getType(); if (map != null && pType != null) { - pType= instantiateType(pType, map, null); + pType= instantiateType(pType, map, -1, null); } if (argType instanceof ICPPUnknownType || isNonTypeArgumentConvertible(pType, argType)) { return new CPPTemplateArgument(arg.getNonTypeValue(), pType); @@ -2082,6 +1900,50 @@ public class CPPTemplates { return null; } + private static boolean compareTemplateParameters(ICPPTemplateParameter[] params1, + ICPPTemplateParameter[] params2) throws DOMException { + int size = params1.length; + if (params2.length != size) { + return false; + } + + for (int i = 0; i < size; i++) { + final ICPPTemplateParameter p1 = params1[i]; + final ICPPTemplateParameter p2 = params2[i]; + if (p1.isParameterPack() != p2.isParameterPack()) + return false; + + boolean pb= p1 instanceof ICPPTemplateTypeParameter; + boolean ab= p2 instanceof ICPPTemplateTypeParameter; + if (pb != ab) + return false; + + if (pb) { + // Both are template type parameters + } else { + pb= p1 instanceof ICPPTemplateNonTypeParameter; + ab= p2 instanceof ICPPTemplateNonTypeParameter; + if (pb != ab) + return false; + + if (pb) { + // Both are non-type parameters + } else { + if (!(p1 instanceof ICPPTemplateTemplateParameter) || + !(p2 instanceof ICPPTemplateTemplateParameter)) { + assert false; + return false; + } + + if (!compareTemplateParameters(((ICPPTemplateTemplateParameter) p1).getTemplateParameters(), + ((ICPPTemplateTemplateParameter) p2).getTemplateParameters()) ) + return false; + } + } + } + return true; + } + /** * Returns whether the template argument arg can be converted to * the same type as paramType using the rules specified in 14.3.2.5. @@ -2172,6 +2034,8 @@ public class CPPTemplates { if (isDependentType(ptmt.getMemberOfClass())) return true; t= ptmt.getType(); + } else if (t instanceof ICPPParameterPackType) { + return true; } else if (t instanceof ITypeContainer) { if (t instanceof IArrayType) { IValue asize= ((IArrayType) t).getSize(); @@ -2197,9 +2061,9 @@ public class CPPTemplates { * Attempts to (partially) resolve an unknown binding with the given arguments. */ private static IBinding resolveUnknown(ICPPUnknownBinding unknown, ICPPTemplateParameterMap tpMap, - ICPPClassSpecialization within) throws DOMException { + int packOffset, ICPPClassSpecialization within) throws DOMException { if (unknown instanceof ICPPDeferredClassInstance) { - return resolveDeferredClassInstance((ICPPDeferredClassInstance) unknown, tpMap, within); + return resolveDeferredClassInstance((ICPPDeferredClassInstance) unknown, tpMap, packOffset, within); } final IBinding owner= unknown.getOwner(); @@ -2207,14 +2071,14 @@ public class CPPTemplates { return unknown; IBinding result = unknown; - IType t = CPPTemplates.instantiateType((IType) owner, tpMap, within); + IType t = CPPTemplates.instantiateType((IType) owner, tpMap, packOffset, within); if (t != null) { t = SemanticUtil.getUltimateType(t, false); if (t instanceof ICPPUnknownBinding) { if (unknown instanceof ICPPUnknownClassInstance) { ICPPUnknownClassInstance ucli= (ICPPUnknownClassInstance) unknown; final ICPPTemplateArgument[] arguments = ucli.getArguments(); - ICPPTemplateArgument[] newArgs = CPPTemplates.instantiateArguments(arguments, tpMap, within); + ICPPTemplateArgument[] newArgs = CPPTemplates.instantiateArguments(arguments, tpMap, packOffset, within); if (!t.equals(owner) && newArgs != arguments) { result= new CPPUnknownClassInstance((ICPPUnknownBinding) t, ucli.getNameCharArray(), newArgs); } @@ -2233,7 +2097,7 @@ public class CPPTemplates { result= CPPSemantics.resolveUnknownName(s, unknown); if (unknown instanceof ICPPUnknownClassInstance && result instanceof ICPPTemplateDefinition) { ICPPTemplateArgument[] newArgs = CPPTemplates.instantiateArguments( - ((ICPPUnknownClassInstance) unknown).getArguments(), tpMap, within); + ((ICPPUnknownClassInstance) unknown).getArguments(), tpMap, packOffset, within); if (result instanceof ICPPClassTemplate) { result = instantiate((ICPPClassTemplate) result, newArgs, false); } @@ -2246,15 +2110,20 @@ public class CPPTemplates { } private static IBinding resolveDeferredClassInstance(ICPPDeferredClassInstance dci, - ICPPTemplateParameterMap tpMap, ICPPClassSpecialization within) { + ICPPTemplateParameterMap tpMap, int packOffset, ICPPClassSpecialization within) { ICPPTemplateArgument[] arguments = dci.getTemplateArguments(); - ICPPTemplateArgument[] newArgs = CPPTemplates.instantiateArguments(arguments, tpMap, within); + ICPPTemplateArgument[] newArgs; + try { + newArgs = CPPTemplates.instantiateArguments(arguments, tpMap, packOffset, within); + } catch (DOMException e) { + return e.getProblem(); + } boolean changed= arguments != newArgs; ICPPClassTemplate classTemplate = dci.getClassTemplate(); - IType specializedClassTemplate= instantiateType(classTemplate, tpMap, within); - if (specializedClassTemplate != classTemplate && specializedClassTemplate instanceof ICPPClassTemplate) { - classTemplate= (ICPPClassTemplate) specializedClassTemplate; + IType classTemplateSpecialization= instantiateType(classTemplate, tpMap, packOffset, within); + if (classTemplateSpecialization != classTemplate && classTemplateSpecialization instanceof ICPPClassTemplate) { + classTemplate= (ICPPClassTemplate) classTemplateSpecialization; changed= true; } @@ -2344,8 +2213,10 @@ public class CPPTemplates { ICPPTemplateParameter[] tps= tdef.getTemplateParameters(); if (numParam < tps.length) { ICPPTemplateArgument arg= tpmap.getArgument(key); - IType type= arg.isNonTypeValue() ? arg.getTypeOfNonTypeValue() : arg.getTypeValue(); - result.put(tps[numParam], type); + if (arg != null) { + IType type= arg.isNonTypeValue() ? arg.getTypeOfNonTypeValue() : arg.getTypeValue(); + result.put(tps[numParam], type); + } } } } 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 980727da09a..63bd3aaf8d8 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 @@ -1588,7 +1588,7 @@ public class CPPVisitor extends ASTQueries { pt = createType(pt, pDtor); pt= adjustParameterType(pt, forFuncType); - if (CPPVisitor.findInnermostDeclarator(pDtor).declaresParameterPack()) { + if (pt != null && CPPVisitor.findInnermostDeclarator(pDtor).declaresParameterPack()) { pt= new CPPParameterPackType(pt); } return pt; @@ -1714,7 +1714,7 @@ public class CPPVisitor extends ASTQueries { } } } - if (isPackExpansion) { + if (type != null && isPackExpansion) { type= new CPPParameterPackType(type); } return type; 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 4bc27bba2e6..91f33848690 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 @@ -34,11 +34,9 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassType; import org.eclipse.cdt.core.dom.ast.cpp.ICPPFunctionType; import org.eclipse.cdt.core.dom.ast.cpp.ICPPMethod; import org.eclipse.cdt.core.dom.ast.cpp.ICPPNamespace; -import org.eclipse.cdt.core.dom.ast.cpp.ICPPParameterPackType; 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.ICPPTemplateArgument; -import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateParameter; import org.eclipse.cdt.core.index.IIndexBinding; import org.eclipse.cdt.core.parser.Keywords; import org.eclipse.cdt.core.parser.util.ArrayUtil; @@ -53,7 +51,6 @@ 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.CPPTemplateArgument; import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPDeferredClassInstance; -import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPUnknownBinding; import org.eclipse.cdt.internal.core.dom.parser.cpp.OverloadableOperator; /** @@ -377,50 +374,6 @@ public class SemanticUtil { return type; } - public static boolean containsParameterPack(IType type) { - while (true) { - if (type instanceof ICPPTemplateParameter) { - return ((ICPPTemplateParameter) type).isParameterPack(); - } else if (type instanceof ICPPDeferredClassInstance) { - // mstodo check the deferred arguments. - return false; - } else if (type instanceof ICPPUnknownBinding) { - try { - IBinding owner= ((ICPPUnknownBinding) type).getOwner(); - if (owner instanceof IType) { - type= (IType) owner; - } else { - return false; - } - } catch (DOMException e) { - return false; - } - } else if (type instanceof IFunctionType) { - final ICPPFunctionType ft = (ICPPFunctionType) type; - final IType r = ft.getReturnType(); - if (containsParameterPack(r)) - return true; - final IType[] ps = ft.getParameterTypes(); - for (IType p : ps) { - if (containsParameterPack(p)) - return true; - } - - } else if (type instanceof ICPPParameterPackType) { - // A pack expansion expands all packs. - return false; - } else if (type instanceof IArrayType) { - final IArrayType atype= (IArrayType) type; - // mstodo check array size - type= atype.getType(); - } else if (type instanceof ITypeContainer) { - type= ((ITypeContainer) type).getType(); - } else { - return false; - } - } - } - public static IType mapToAST(IType type, IASTNode node) { if (type instanceof IFunctionType) { final ICPPFunctionType ft = (ICPPFunctionType) type; 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 new file mode 100644 index 00000000000..f14876af10f --- /dev/null +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/TemplateArgumentDeduction.java @@ -0,0 +1,629 @@ +/******************************************************************************* + * Copyright (c) 2009 Wind River Systems, Inc. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Markus Schorn - initial API and implementation + *******************************************************************************/ +package org.eclipse.cdt.internal.core.dom.parser.cpp.semantics; + +import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.*; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.BitSet; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import org.eclipse.cdt.core.dom.ast.DOMException; +import org.eclipse.cdt.core.dom.ast.IArrayType; +import org.eclipse.cdt.core.dom.ast.IBasicType; +import org.eclipse.cdt.core.dom.ast.IBinding; +import org.eclipse.cdt.core.dom.ast.IFunctionType; +import org.eclipse.cdt.core.dom.ast.IPointerType; +import org.eclipse.cdt.core.dom.ast.IQualifierType; +import org.eclipse.cdt.core.dom.ast.IType; +import org.eclipse.cdt.core.dom.ast.ITypedef; +import org.eclipse.cdt.core.dom.ast.IValue; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPBase; +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.ICPPFunctionTemplate; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPParameterPackType; +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.ICPPTemplateArgument; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateDefinition; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateInstance; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateParameter; +import org.eclipse.cdt.internal.core.dom.parser.Value; +import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPBasicType; +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.CPPTemplateParameterMap; +import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPUnknownBinding; + +/** + * Algorithms for deducing template arguments in various contexts. + */ +public class TemplateArgumentDeduction { + /** + * Deduce arguments for a template function from the template id + the template function parameters. + * 14.8.2.1 + */ + static ICPPTemplateArgument[] deduceForFunctionCall(ICPPFunctionTemplate template, + ICPPTemplateArgument[] tmplArgs, IType[] fnArgs, BitSet argIsLValue, CPPTemplateParameterMap map) + throws DOMException { + final ICPPTemplateParameter[] tmplParams = template.getTemplateParameters(); + final int numTmplParams = tmplParams.length; + final int numTmplArgs = tmplArgs.length; + + tmplArgs= SemanticUtil.getSimplifiedArguments(tmplArgs); + ICPPTemplateParameter tmplParam= null; + int packOffset= -1; + for (int i = 0; i < numTmplArgs; i++) { + if (packOffset < 0 || tmplParam == null) { + if (i >= numTmplParams) + return null; + + tmplParam= tmplParams[i]; + if (tmplParam.isParameterPack()) { + packOffset= i; + } + } + ICPPTemplateArgument tmplArg= tmplArgs[i]; + tmplArg= CPPTemplates.matchTemplateParameterAndArgument(tmplParam, tmplArg, map); + if (tmplArg == null) + return null; + + if (packOffset < 0) { + map.put(tmplParam, tmplArg); + } + } + + if (packOffset >= 0) { + final int packSize= tmplArgs.length- packOffset; + ICPPTemplateArgument[] pack= new ICPPTemplateArgument[packSize]; + System.arraycopy(tmplArgs, packOffset, pack, 0, packSize); + map.put(tmplParam, pack); + } + + if (!deduceFromFunctionArgs(template, fnArgs, argIsLValue, map, false)) + return null; + + List result= new ArrayList(numTmplParams); + for (ICPPTemplateParameter tpar : tmplParams) { + if (tpar.isParameterPack()) { + ICPPTemplateArgument[] deducedArgs= map.getPackExpansion(tpar); + if (deducedArgs == null) + return null; + result.addAll(Arrays.asList(deducedArgs)); + } else { + ICPPTemplateArgument deducedArg= map.getArgument(tpar); + if (deducedArg == null) + return null; + + result.add(deducedArg); + } + } + return result.toArray(new ICPPTemplateArgument[result.size()]); + } + + /** + * Deduce arguments for a user defined conversion template + * 14.8.2.3 + */ + static ICPPTemplateArgument[] deduceForConversion(ICPPFunctionTemplate template, + IType conversionType, CPPTemplateParameterMap map) throws DOMException { + final ICPPTemplateParameter[] tmplParams = template.getTemplateParameters(); + final int length = tmplParams.length; + + ICPPTemplateArgument[] result = new ICPPTemplateArgument[length]; + IType a= SemanticUtil.getSimplifiedType(conversionType); + IType p= template.getType().getReturnType(); + p= getArgumentTypeForDeduction(p, a instanceof ICPPReferenceType); + a= SemanticUtil.getNestedType(a, SemanticUtil.REF | SemanticUtil.TDEF); + TemplateArgumentDeduction deduct= new TemplateArgumentDeduction(tmplParams, null, map, 0); + if (!deduct.fromType(p, a)) { + return null; + } + + for (int i = 0; i < length; i++) { + if (result[i] == null) { + ICPPTemplateArgument deducedArg= map.getArgument(tmplParams[i]); + if (deducedArg == null) + return null; + result[i]= deducedArg; + } + } + return result; + } + + /** + * Deduces the mapping for the template parameters from the function parameters, + * returns false if there is no mapping. + */ + static boolean deduceFromFunctionArgs(ICPPFunctionTemplate template, IType[] fnArgs, BitSet argIsLValue, + CPPTemplateParameterMap map, boolean checkExactMatch) { + try { + IType[] fnPars = template.getType().getParameterTypes(); + final int fnParCount = fnPars.length; + if (fnParCount == 0) + return true; + + final ICPPTemplateParameter[] tmplPars = template.getTemplateParameters(); + TemplateArgumentDeduction deduct= new TemplateArgumentDeduction(tmplPars, map, new CPPTemplateParameterMap(fnParCount), 0); + IType fnParPack= null; + for (int j= 0; j < fnArgs.length; j++) { + IType par; + if (fnParPack != null) { + par= fnParPack; + deduct.incPackOffset(); + } else if (j < fnParCount) { + par= fnPars[j]; + if (par instanceof ICPPParameterPackType) { + // must be the last parameter. + if (j != fnParCount-1) + return false; + + par= fnParPack= ((ICPPParameterPackType) par).getType(); + deduct= new TemplateArgumentDeduction(deduct, fnArgs.length-j); + } + } else { + break; + } + + par= CPPTemplates.instantiateType(par, map, -1, null); + if (!CPPTemplates.isValidType(par)) + return false; + + boolean isDependentPar= CPPTemplates.isDependentType(par); + if (checkExactMatch || isDependentPar) { + boolean isReferenceTypeParameter= false; + IType arg = fnArgs[j]; + par= SemanticUtil.getNestedType(par, SemanticUtil.TDEF); // adjustParameterType preserves typedefs + // 14.8.2.1-2 + if (par instanceof ICPPReferenceType) { + // If P is an rvalue reference to a cv-unqualified template parameter and the argument is an + // lvalue, the type A& “lvalue reference to A” is used in place of A for type deduction. + isReferenceTypeParameter= true; + final ICPPReferenceType refPar = (ICPPReferenceType) par; + if (refPar.isRValueReference() && refPar.getType() instanceof ICPPTemplateParameter && argIsLValue.get(j)) { + arg= new CPPReferenceType(getSimplifiedType(arg), false); + } else { + arg= getArgumentTypeForDeduction(arg, true); + } + par= SemanticUtil.getNestedType(par, SemanticUtil.REF | SemanticUtil.TDEF); + } else { + arg= getArgumentTypeForDeduction(arg, false); + } + + if (!checkExactMatch) { + // 14.8.2.1-3 + 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 { + 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 (isDependentPar && !deduct.fromType(par, arg)) { + return false; + } + if (checkExactMatch) { + IType instantiated= CPPTemplates.instantiateType(par, deduct.fDeducedArgs, deduct.fPackOffset, null); + if (!instantiated.isSameType(arg)) + return false; + } + } + } + if (!deduct.fExplicitArgs.mergeToExplicit(deduct.fDeducedArgs)) + return false; + + return verifyDeduction(tmplPars, map, true); + } catch (DOMException e) { + } + return false; + } + + /** + * 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) { + final ICPPTemplateInstance inst = (ICPPTemplateInstance) a; + ICPPClassTemplate tmpl= getPrimaryTemplate(inst); + if (pTemplate.isSameType(tmpl)) + return a; + } + if (maxdepth-- > 0) { + for (ICPPBase cppBase : a.getBases()) { + IBinding base= cppBase.getBaseClass(); + if (base instanceof ICPPClassType) { + final ICPPClassType inst= findBaseInstance((ICPPClassType) base, pTemplate, maxdepth); + if (inst != null) + return inst; + } + } + } + return null; + } + + + private static ICPPClassTemplate getPrimaryTemplate(ICPPTemplateInstance inst) throws DOMException { + ICPPTemplateDefinition template= inst.getTemplateDefinition(); + if (template instanceof ICPPClassTemplatePartialSpecialization) { + return ((ICPPClassTemplatePartialSpecialization) template).getPrimaryClassTemplate(); + } else if (template instanceof ICPPClassTemplate) { + return (ICPPClassTemplate) template; + } + return null; + } + + /** + * 14.8.2.1-2 + * if P is not a reference type + * - If A is an array type, the pointer type produced by the array-to-pointer conversion is used instead + * - If A is a function type, the pointer type produced by the function-to-pointer conversion is used instead + * - If A is a cv-qualified type, the top level cv-qualifiers are ignored for type deduction + * + * Also 14.8.2.3-2 where the same logics is used in reverse. + */ + private static IType getArgumentTypeForDeduction(IType type, boolean parameterIsAReferenceType) { + type = SemanticUtil.getSimplifiedType(type); + if (type instanceof ICPPReferenceType) { + type = ((ICPPReferenceType) type).getType(); + } + IType result = type; + if (!parameterIsAReferenceType) { + if (type instanceof IArrayType) { + result = new CPPPointerType(((IArrayType) type).getType()); + } else if (type instanceof IFunctionType) { + result = new CPPPointerType(type); + } else { + result = SemanticUtil.getNestedType(type, TDEF | ALLCVQ ); + } + } + return result; + } + + + /** + * Deduces the template parameter mapping from pairs of template arguments. + */ + public static boolean fromTemplateArguments(final ICPPTemplateParameter[] pars, final ICPPTemplateArgument[] p, final ICPPTemplateArgument[] a, CPPTemplateParameterMap map) throws DOMException { + TemplateArgumentDeduction deduct= new TemplateArgumentDeduction(pars, null, map, 0); + final int len= a.length; + if (p == null || p.length != len) { + return false; + } + for (int j=0; j fTemplateParameterPacks; + private int fPackOffset; + private final int fPackSize; + + private TemplateArgumentDeduction(ICPPTemplateParameter[] tpars, CPPTemplateParameterMap explicit, CPPTemplateParameterMap result, int packSize) { + fExplicitArgs= explicit; + fDeducedArgs= result; + fPackSize= packSize; + fPackOffset= packSize > 0 ? 0 : -1; + for (ICPPTemplateParameter tpar : tpars) { + if (tpar.isParameterPack()) { + if (fTemplateParameterPacks == null) { + fTemplateParameterPacks= new HashSet(); + } + fTemplateParameterPacks.add(tpar.getParameterID()); + } + } + } + + private TemplateArgumentDeduction(TemplateArgumentDeduction base, int packSize) { + fExplicitArgs= base.fExplicitArgs; + fDeducedArgs= base.fDeducedArgs; + fTemplateParameterPacks= base.fTemplateParameterPacks; + fPackSize= packSize; + fPackOffset= packSize > 0 ? 0 : -1; + } + + + private void incPackOffset() { + fPackOffset++; + assert fPackOffset < fPackSize; + } + /** + * Deduces the template parameter mapping from one pair of template arguments. + */ + private boolean fromTemplateArgument(ICPPTemplateArgument p, ICPPTemplateArgument a) throws DOMException { + if (p.isNonTypeValue() != a.isNonTypeValue()) + return false; + + 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); + } + return old.isSameValue(a); + } + + IValue sval= a.getNonTypeValue(); + return tval.equals(sval); + } + + return fromType(p.getTypeValue(), a.getTypeValue()); + } + + + private boolean fromType(IType p, IType a) throws DOMException { + while (p != null) { + while (a instanceof ITypedef) + a = ((ITypedef) a).getType(); + if (p instanceof IBasicType) { + return p.isSameType(a); + } else if (p instanceof ICPPPointerToMemberType) { + if (!(a instanceof ICPPPointerToMemberType)) + return false; + if (!fromType(((ICPPPointerToMemberType) p).getMemberOfClass(), + ((ICPPPointerToMemberType) a).getMemberOfClass())) { + return false; + } + p = ((ICPPPointerToMemberType) p).getType(); + a = ((ICPPPointerToMemberType) a).getType(); + } else if (p instanceof IPointerType) { + if (!(a instanceof IPointerType)) { + return false; + } + p = ((IPointerType) p).getType(); + a = ((IPointerType) a).getType(); + } else if (p instanceof ICPPReferenceType) { + if (!(a instanceof ICPPReferenceType)) { + return false; + } + p = ((ICPPReferenceType) p).getType(); + a = ((ICPPReferenceType) a).getType(); + } else if (p instanceof IArrayType) { + if (!(a instanceof IArrayType)) { + return false; + } + IArrayType aa= (IArrayType) a; + IArrayType pa= (IArrayType) p; + IValue as= aa.getSize(); + IValue ps= pa.getSize(); + if (as != ps) { + if (as == null || ps == null) + return false; + + int parID= Value.isTemplateParameter(ps); + if (parID >= 0) { + ICPPTemplateArgument old= fDeducedArgs.getArgument(parID, fPackOffset); + if (old == null) { + if (!deduce(parID, new CPPTemplateArgument(as, new CPPBasicType(ICPPBasicType.Kind.eInt, 0)))) { + return false; + } + } else if (!as.equals(old.getNonTypeValue())) { + return false; + } + } else if (!as.equals(as)) { + return false; + } + } + p = pa.getType(); + a = aa.getType(); + } else if (p instanceof IQualifierType) { + IType uqp = SemanticUtil.getNestedType(p, ALLCVQ); + IType uqa = SemanticUtil.getNestedType(a, ALLCVQ); + if (uqp instanceof ICPPTemplateParameter) { + CVQualifier remaining= SemanticUtil.getCVQualifier(a).remove(SemanticUtil.getCVQualifier(p)); + if (remaining != CVQualifier._) { + uqa= SemanticUtil.addQualifiers(uqa, remaining.isConst(), remaining.isVolatile()); + } + } + a= uqa; + p= uqp; + } else if (p instanceof IFunctionType) { + if (!(a instanceof IFunctionType)) + return false; + return fromFunctionType((IFunctionType) p, (IFunctionType) a); + } else if (p instanceof ICPPTemplateParameter) { + ICPPTemplateArgument current= fDeducedArgs.getArgument(((ICPPTemplateParameter) p).getParameterID(), fPackOffset); + if (current != null) { + if (current.isNonTypeValue()) + return false; + return current.getTypeValue().isSameType(a); + } + if (a == null) + return false; + return deduce(((ICPPTemplateParameter)p).getParameterID(), new CPPTemplateArgument(a)); + } else if (p instanceof ICPPTemplateInstance) { + if (!(a instanceof ICPPTemplateInstance)) + return false; + return fromTemplateInstance((ICPPTemplateInstance) p, (ICPPTemplateInstance) a); + } else if (p instanceof ICPPUnknownBinding) { + return true; // An unknown type may match anything. + } else { + return p.isSameType(a); + } + } + + return false; + } + + private boolean fromTemplateInstance(ICPPTemplateInstance pInst, ICPPTemplateInstance aInst) + throws DOMException { + ICPPClassTemplate pTemplate= getPrimaryTemplate(pInst); + ICPPClassTemplate aTemplate= getPrimaryTemplate(aInst); + if (pTemplate == null || aTemplate == null || !aTemplate.isSameType(pTemplate)) + return false; + + // Check for being a non-deduced context. + final ICPPTemplateArgument[] pArgs = pInst.getTemplateArguments(); + for (int i = 0; i < pArgs.length-1; i++) { + if (pArgs[i].isPackExpansion()) + return true; // non-deduced context + } + + final ICPPTemplateArgument[] aArgs = aInst.getTemplateArguments(); + if (pArgs.length != aArgs.length) { + if (pArgs.length == 0 || pArgs.length > aArgs.length+1) + return false; + ICPPTemplateArgument lastPParam= pArgs[pArgs.length-1]; + if (!lastPParam.isPackExpansion()) + return false; + } + + ICPPTemplateArgument expansionPattern= null; + TemplateArgumentDeduction deduct= this; + for (int i = 0; i < aArgs.length; i++) { + ICPPTemplateArgument p; + if (expansionPattern != null) { + p= expansionPattern; + deduct.incPackOffset(); + p= CPPTemplates.instantiateArgument(p, fExplicitArgs, deduct.fPackOffset, null); + if (!CPPTemplates.isValidArgument(p)) + return false; + } else { + p= pArgs[i]; + if (p.isPackExpansion()) { + p= expansionPattern= p.getExpansionPattern(); + deduct= new TemplateArgumentDeduction(this, aArgs.length-i); + p= CPPTemplates.instantiateArgument(p, fExplicitArgs, deduct.fPackOffset, null); + if (!CPPTemplates.isValidArgument(p)) + return false; + } + } + if (!deduct.fromTemplateArgument(p, aArgs[i])) + return false; + } + return true; + } + + private boolean fromFunctionType(IFunctionType ftp, IFunctionType fta) throws DOMException { + if (!fromType(ftp.getReturnType(), fta.getReturnType())) + return false; + + IType[] pParams = ftp.getParameterTypes(); + IType[] aParams = fta.getParameterTypes(); + if (pParams.length != aParams.length) { + if (pParams.length == 0 || pParams.length > aParams.length+1) + return false; + IType lastPParam= pParams[pParams.length-1]; + if (!(lastPParam instanceof ICPPParameterPackType)) + return false; + } + IType parameterPack= null; + TemplateArgumentDeduction deduct= this; + for (int i = 0; i < aParams.length; i++) { + IType p; + if (parameterPack != null) { + p= parameterPack; + deduct.incPackOffset(); + p= CPPTemplates.instantiateType(p, fExplicitArgs, deduct.fPackOffset, null); + if (!CPPTemplates.isValidType(p)) + return false; + } else { + p= pParams[i]; + if (p instanceof ICPPParameterPackType) { + p= parameterPack= ((ICPPParameterPackType) p).getType(); + deduct= new TemplateArgumentDeduction(this, aParams.length-i); + p= CPPTemplates.instantiateType(p, fExplicitArgs, deduct.fPackOffset, null); + if (!CPPTemplates.isValidType(p)) + return false; + } + } + if (!deduct.fromType(p, aParams[i])) + return false; + } + return true; + } + + private boolean deduce(int parID, ICPPTemplateArgument arg) { + if (fTemplateParameterPacks != null && fTemplateParameterPacks.contains(parID)) { + if (fPackSize == 0) + return false; + return fDeducedArgs.putPackElement(parID, fPackOffset, arg, fPackSize); + } + fDeducedArgs.put(parID, arg); + return true; + } +} diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/index/composite/cpp/CPPCompositesFactory.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/index/composite/cpp/CPPCompositesFactory.java index 2fb5cfaa313..92a942f84fa 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/index/composite/cpp/CPPCompositesFactory.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/index/composite/cpp/CPPCompositesFactory.java @@ -38,8 +38,8 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPMethod; import org.eclipse.cdt.core.dom.ast.cpp.ICPPNamespace; import org.eclipse.cdt.core.dom.ast.cpp.ICPPNamespaceAlias; import org.eclipse.cdt.core.dom.ast.cpp.ICPPNamespaceScope; -import org.eclipse.cdt.core.dom.ast.cpp.ICPPParameterPackType; import org.eclipse.cdt.core.dom.ast.cpp.ICPPParameter; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPParameterPackType; 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; @@ -171,7 +171,7 @@ public class CPPCompositesFactory extends AbstractCompositeFactory { ICPPParameterPackType rt= (ICPPParameterPackType) rtype; IType r= rt.getType(); IType r2= getCompositeType(r); - if (r != r2) { + if (r != r2 && r2 != null) { return new CPPParameterPackType(r2); } return rt; diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/index/composite/cpp/TemplateInstanceUtil.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/index/composite/cpp/TemplateInstanceUtil.java index 91bd2cbe0e6..f21db85c66e 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/index/composite/cpp/TemplateInstanceUtil.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/index/composite/cpp/TemplateInstanceUtil.java @@ -43,7 +43,12 @@ public class TemplateInstanceUtil { try { for (Integer key : keys) { ICPPTemplateArgument arg= preresult.getArgument(key); - result.put(key, convert(cf, arg)); + if (arg != null) { + result.put(key, convert(cf, arg)); + } else { + ICPPTemplateArgument[] pack= preresult.getPackExpansion(key); + result.put(key, convert(cf, pack)); + } } } catch(DOMException de) { CCorePlugin.log(de); diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/PDOM.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/PDOM.java index b6684040c5b..65d2f5e7980 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/PDOM.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/PDOM.java @@ -188,10 +188,11 @@ public class PDOM extends PlatformObject implements IPDOM { * 93.0 - further simplification of basic types, bug 231859. * 94.0 - new model for storing types, bug 294306. * 95.0 - parameter packs, bug 294730. + * 96.0 - storing pack expansions in the template parameter map, bug 294730. */ - private static final int MIN_SUPPORTED_VERSION= version(95, 0); - private static final int MAX_SUPPORTED_VERSION= version(95, Short.MAX_VALUE); - private static final int DEFAULT_VERSION = version(95, 0); + private static final int MIN_SUPPORTED_VERSION= version(96, 0); + private static final int MAX_SUPPORTED_VERSION= version(96, Short.MAX_VALUE); + private static final int DEFAULT_VERSION = version(96, 0); private static int version(int major, int minor) { return (major << 16) + minor; diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/PDOMASTAdapter.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/PDOMASTAdapter.java index e1ec1424b2c..971f5299528 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/PDOMASTAdapter.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/PDOMASTAdapter.java @@ -36,6 +36,7 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassType; import org.eclipse.cdt.core.dom.ast.cpp.ICPPConstructor; import org.eclipse.cdt.core.dom.ast.cpp.ICPPField; import org.eclipse.cdt.core.dom.ast.cpp.ICPPMethod; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateParameter; import org.eclipse.cdt.core.index.IIndexBinding; import org.eclipse.cdt.core.parser.IToken; import org.eclipse.core.runtime.CoreException; @@ -485,25 +486,25 @@ public class PDOMASTAdapter { char[] name= binding.getNameCharArray(); if (name.length == 0) { if (binding instanceof IEnumeration) { - name= ASTTypeUtil.createNameForAnonymous(binding); + name = ASTTypeUtil.createNameForAnonymous(binding); if (name != null) { if (binding instanceof ICPPBinding) { return new AnonymousCPPEnumeration(name, (IEnumeration) binding); } return new AnonymousEnumeration(name, (IEnumeration) binding); } - } - else if (binding instanceof ICPPClassType) { - name= ASTTypeUtil.createNameForAnonymous(binding); + } else if (binding instanceof ICPPClassType) { + name = ASTTypeUtil.createNameForAnonymous(binding); if (name != null) { return new AnonymousClassType(name, (ICPPClassType) binding); } - } - else if (binding instanceof ICompositeType) { - name= ASTTypeUtil.createNameForAnonymous(binding); + } else if (binding instanceof ICompositeType) { + name = ASTTypeUtil.createNameForAnonymous(binding); if (name != null) { return new AnonymousCompositeType(name, (ICompositeType) binding); } + } else if (binding instanceof ICPPTemplateParameter) { + return binding; } return null; } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/cpp/PDOMCPPTemplateParameterMap.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/cpp/PDOMCPPTemplateParameterMap.java index 0e5e58141ab..28d9c46d8a7 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/cpp/PDOMCPPTemplateParameterMap.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/cpp/PDOMCPPTemplateParameterMap.java @@ -22,15 +22,13 @@ import org.eclipse.cdt.internal.core.pdom.db.Database; import org.eclipse.cdt.internal.core.pdom.dom.PDOMLinkage; import org.eclipse.cdt.internal.core.pdom.dom.PDOMNode; import org.eclipse.cdt.internal.core.pdom.dom.PDOMValue; -import org.eclipse.core.runtime.Assert; import org.eclipse.core.runtime.CoreException; /** * Collects methods to store an argument list in the database */ public class PDOMCPPTemplateParameterMap { - private static final int PARAMPOS_OFFSET= 0; - private static final int TYPE_OFFSET= PARAMPOS_OFFSET + 4; + private static final int TYPE_OFFSET= 0; private static final int VALUE_OFFSET= TYPE_OFFSET + Database.TYPE_SIZE; private static final int NODE_SIZE = VALUE_OFFSET + Database.PTR_SIZE; @@ -42,43 +40,74 @@ public class PDOMCPPTemplateParameterMap { final PDOMLinkage linkage= parent.getLinkage(); final Database db= linkage.getDB(); Integer[] keys= map.getAllParameterPositions(); - final short len= (short) Math.min(keys.length, (Database.MAX_MALLOC_SIZE-2)/NODE_SIZE); - final long block= db.malloc(2+NODE_SIZE*len); - long p= block; - - db.putShort(p, len); p+=2; - for (int i=0; i Database.MAX_MALLOC_SIZE) + break; + dataSize += delta; + keyLen++; } + final long block= db.malloc(dataSize); + long p= block; + db.putShort(p, (short)keyLen); p+=2; + for (final Integer paramId : keys) { + if (--keyLen < 0) + break; + db.putInt(p, paramId); p+=4; + final ICPPTemplateArgument arg = map.getArgument(paramId); + if (arg != null) { + db.putShort(p, (short) -1); p+=2; + storeArgument(db, linkage, p, arg); p+= NODE_SIZE; + } else { + final ICPPTemplateArgument[] args = map.getPackExpansion(paramId); + db.putShort(p, (short) args.length); p+=2; + for (ICPPTemplateArgument a : args) { + storeArgument(db, linkage, p, a); p+= NODE_SIZE; + } + } + } + assert p == block+dataSize; return block; } + private static void storeArgument(final Database db, final PDOMLinkage linkage, long p, + final ICPPTemplateArgument arg) throws CoreException { + if (arg.isNonTypeValue()) { + linkage.storeType(p + TYPE_OFFSET, arg.getTypeOfNonTypeValue()); + db.putRecPtr(p+VALUE_OFFSET, PDOMValue.store(db, linkage, arg.getNonTypeValue())); + } else { + linkage.storeType(p + TYPE_OFFSET, arg.getTypeValue()); + } + } /** * Clears the map in the database. */ - public static void clearMap(PDOMNode parent, int rec) throws CoreException { + public static void clearMap(PDOMNode parent, final int record) throws CoreException { final PDOMLinkage linkage= parent.getLinkage(); final Database db= linkage.getDB(); - final short len= db.getShort(rec); - Assert.isTrue(len >= 0 && len <= (Database.MAX_MALLOC_SIZE-2)/NODE_SIZE); - rec+=2; + long p= record; + final short len= db.getShort(p); p+= 2; + for (int i=0; i= 0 && len <= (Database.MAX_MALLOC_SIZE-2)/NODE_SIZE); if (len == 0) { return CPPTemplateParameterMap.EMPTY; } @@ -97,22 +125,37 @@ public class PDOMCPPTemplateParameterMap { rec+=2; CPPTemplateParameterMap result= new CPPTemplateParameterMap(len); for (int i=0; i