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 e73f0ec9d8b..7872bd93ab5 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 @@ -4816,8 +4816,16 @@ public class AST2TemplateTests extends AST2CPPTestBase { // int main() { // foo(0); // } - public void testFunctionTemplateOrdering_388805() throws Exception { - parseAndCheckBindings(); + public void testFunctionTemplateOrdering_DR1395_388805() throws Exception { + String code = getAboveComment(); + BindingAssertionHelper bh = new AST2AssertionHelper(code, CPP); + + ICPPFunctionTemplate f1 = bh.assertNonProblem("foo(A)", 3); + ICPPFunctionTemplate f2 = bh.assertNonProblem("foo(A, B...)", 3); + + ICPPTemplateInstance t; + t = bh.assertNonProblem("foo(0)", 3); + assertSame(f1, t.getTemplateDefinition()); } // template @@ -11200,4 +11208,56 @@ public class AST2TemplateTests extends AST2CPPTestBase { public void testDisambiguateFunctionWithDefaultArgumentDeclaration_541474() throws Exception { parseAndCheckBindings(); } + + // template + // void info(T a) { + // } + // template + // void info(int a, Args... args) { + // // this is more specialized + // } + // int main( ) { + // info(1); + // } + public void testDisambiguateFunctionUnusedPack_541474() throws Exception { + parseAndCheckBindings(); + } + + // template + // void foo(A, B=0); // this overload is taken + // + // template + // void foo(A, B...); + // + // int main() { + // foo(0); + // } + public void testDisambiguateFunctionUnusedPackVsDefault_541474() throws Exception { + String code = getAboveComment(); + BindingAssertionHelper bh = new AST2AssertionHelper(code, CPP); + + ICPPFunctionTemplate f1 = bh.assertNonProblem("foo(A, B=0)", 3); + ICPPFunctionTemplate f2 = bh.assertNonProblem("foo(A, B...)", 3); + + ICPPTemplateInstance t; + t = bh.assertNonProblem("foo(0)", 3); + assertSame(f1, t.getTemplateDefinition()); + } + + // template + // void foo(A, B=0, C...); + // + // template + // void foo(A, B...); + // + // int main() { + // foo(0); + // } + public void testDisambiguateFunctionUnusedPackVsDefault2_541474() throws Exception { + BindingAssertionHelper bh = new AST2AssertionHelper(getAboveComment(), CPP); + // clang (7.0.0) and gcc (7.3.1) disagree, clang thinks this is ambiguous + // which seems correct according to [temp.deduct.partial] p11 + bh.assertProblem("foo(0)", 3); + } + } 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 5a6327ca3bd..f8703278cc8 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 @@ -27,6 +27,7 @@ import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUti import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.getNestedType; import java.util.ArrayList; +import java.util.Arrays; import java.util.HashSet; import java.util.List; import java.util.Map; @@ -2504,6 +2505,23 @@ public class CPPTemplates { return null; } + /** + * N4659: [temp.deduct.partial] p11 + */ + static int disambiguateTrailingParameterPack(ICPPFunctionTemplate f1, ICPPFunctionTemplate f2, int nExplicitArgs) { + ICPPTemplateParameter[] f1params = f1.getTemplateParameters(); + ICPPTemplateParameter[] f2params = f2.getTemplateParameters(); + boolean f1hasTrailingPack = f1params[f1params.length - 1].isParameterPack(); + boolean f2hasTrailingPack = f2params[f2params.length - 1].isParameterPack(); + if (f1hasTrailingPack && f1params.length > nExplicitArgs && !f2hasTrailingPack) { + return -1; + } else if (f2hasTrailingPack && f2params.length > nExplicitArgs && !f1hasTrailingPack) { + return 1; + } else { + return 0; + } + } + /** * 14.5.6.2 Partial ordering of function templates * @@ -2527,8 +2545,9 @@ public class CPPTemplates { int s1 = compareSpecialization(f1, f2, mode, nExplicitArgs); int s2 = compareSpecialization(f2, f1, mode, nExplicitArgs); - if (s1 == s2) - return 0; + if (s1 == s2) { + return disambiguateTrailingParameterPack(f1, f2, nExplicitArgs); + } if (s1 < 0 || s2 > 0) return -1; assert s2 < 0 || s1 > 0; @@ -2576,25 +2595,24 @@ public class CPPTemplates { return arg; } - private static ICPPFunctionType getFunctionTypeIgnoringParametersWithDefaults(ICPPFunction function, + /** + * [temp.func.order] p5: Considers only parameters for which there are explicit call arguments. + * + * Since at this point non-viable functions are already excluded, it is safe to just ignore extra parameters + * without checking if they can be ignored, i.e. without checking if they are function parameter packs, + * parameters with default arguments, or ellipsis parameter. + */ + private static ICPPFunctionType getFunctionTypeIgnoringParametersWithoutExplicitArguments(ICPPFunction function, int nExplicitArgs) { - ICPPParameter[] parameters = function.getParameters(); - IType[] parameterTypes = new IType[parameters.length]; - int i; - for (i = 0; i < parameters.length; ++i) { - ICPPParameter parameter = parameters[i]; - if (i < nExplicitArgs || !parameter.hasDefaultValue()) { - parameterTypes[i] = parameter.getType(); - } else { - break; - } - } ICPPFunctionType originalType = function.getType(); - if (i == parameters.length) // No parameters with default arguments. + if (nExplicitArgs < function.getParameters().length) { + IType[] parameterTypesWithExplicitArguments = Arrays.copyOf(originalType.getParameterTypes(), + nExplicitArgs); + return new CPPFunctionType(originalType.getReturnType(), parameterTypesWithExplicitArguments, + originalType.isConst(), originalType.isVolatile(), originalType.hasRefQualifier(), + originalType.isRValueReference(), originalType.takesVarArgs()); + } else return originalType; - return new CPPFunctionType(originalType.getReturnType(), ArrayUtil.trim(parameterTypes), originalType.isConst(), - originalType.isVolatile(), originalType.hasRefQualifier(), originalType.isRValueReference(), - originalType.takesVarArgs()); } private static int compareSpecialization(ICPPFunctionTemplate f1, ICPPFunctionTemplate f2, TypeSelection mode, @@ -2604,9 +2622,8 @@ public class CPPTemplates { return -1; final ICPPFunctionType ft2 = f2.getType(); - // Ignore parameters with default arguments in the transformed function template - // as per [temp.func.order] p5. - final ICPPFunctionType transFt1 = getFunctionTypeIgnoringParametersWithDefaults(transF1, nExplicitArgs); + final ICPPFunctionType transFt1 = getFunctionTypeIgnoringParametersWithoutExplicitArguments(transF1, + nExplicitArgs); IType[] pars; IType[] args; switch (mode) {