mirror of
https://github.com/eclipse-cdt/cdt
synced 2025-04-21 21:52:10 +02:00
Bug 541717 - Partial ordering and DR1395
- As of [temp.func.order] p5 only parameters for which there are explicit arguments should be considered. - Implement [temp.deduct.partial] p11 (resolution of DR1395). Change-Id: I56262229a6fe4717c22aac814aa9ea42eb37a10d Signed-off-by: Hannes Vogt <hannes@havogt.de>
This commit is contained in:
parent
12207e79db
commit
2fc42590fb
2 changed files with 100 additions and 23 deletions
|
@ -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 <typename T>
|
||||
|
@ -11200,4 +11208,56 @@ public class AST2TemplateTests extends AST2CPPTestBase {
|
|||
public void testDisambiguateFunctionWithDefaultArgumentDeclaration_541474() throws Exception {
|
||||
parseAndCheckBindings();
|
||||
}
|
||||
|
||||
// template<typename T>
|
||||
// void info(T a) {
|
||||
// }
|
||||
// template<typename... Args>
|
||||
// void info(int a, Args... args) {
|
||||
// // this is more specialized
|
||||
// }
|
||||
// int main( ) {
|
||||
// info(1);
|
||||
// }
|
||||
public void testDisambiguateFunctionUnusedPack_541474() throws Exception {
|
||||
parseAndCheckBindings();
|
||||
}
|
||||
|
||||
// template<typename A, typename B = int>
|
||||
// void foo(A, B=0); // this overload is taken
|
||||
//
|
||||
// template<typename A, typename... B>
|
||||
// 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<typename A, typename B = int, typename... C>
|
||||
// void foo(A, B=0, C...);
|
||||
//
|
||||
// template<typename A, typename... B>
|
||||
// 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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
Loading…
Add table
Reference in a new issue