1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-04-29 19:45:01 +02:00

Ordering of function templates, bug 293468.

This commit is contained in:
Markus Schorn 2009-10-28 07:16:12 +00:00
parent e81078bb95
commit 1ac9f8bc6c
4 changed files with 116 additions and 106 deletions

View file

@ -4211,4 +4211,20 @@ public class AST2TemplateTests extends AST2BaseTest {
bh.assertNonProblem("f4(i);", 2, ICPPFunction.class); bh.assertNonProblem("f4(i);", 2, ICPPFunction.class);
bh.assertProblem("f3(&cd);", 2); bh.assertProblem("f3(&cd);", 2);
} }
// template<typename T> struct C {};
// template<typename T, typename V> void f(T, C<V>) {}
// template<typename T> void f(T, C<int>) {}
//
// void test() {
// char ch;
// C<int> cint;
// C<char> cchar;
// f(ch, cchar);
// f(ch, cint);
// }
public void testFunctionTemplateOrdering_293468() throws Exception {
final String code= getAboveComment();
parseAndCheckBindings(code, ParserLanguage.CPP);
}
} }

View file

@ -42,6 +42,7 @@ import org.eclipse.cdt.internal.core.dom.parser.c.CASTTypeId;
import org.eclipse.cdt.internal.core.dom.parser.c.CVisitor; import org.eclipse.cdt.internal.core.dom.parser.c.CVisitor;
import org.eclipse.cdt.internal.core.dom.parser.c.ICInternalBinding; import org.eclipse.cdt.internal.core.dom.parser.c.ICInternalBinding;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTTypeId; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTTypeId;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPBasicType;
import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPInternalBinding; import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPInternalBinding;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPVisitor; 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.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil;
@ -246,6 +247,9 @@ public class ASTTypeUtil {
result.append(Keywords.cpRBRACKET); result.append(Keywords.cpRBRACKET);
} else if (type instanceof IBasicType) { } else if (type instanceof IBasicType) {
IBasicType basicType= (IBasicType) type; IBasicType basicType= (IBasicType) type;
if (basicType.getModifiers() == CPPBasicType.UNIQUE_TYPE_QUALIFIER) {
return "@" + String.valueOf(basicType.hashCode()); //$NON-NLS-1$
}
final Kind kind = basicType.getKind(); final Kind kind = basicType.getKind();
if (basicType.isSigned()) { if (basicType.isSigned()) {
// 3.9.1.2: signed integer types // 3.9.1.2: signed integer types

View file

@ -32,7 +32,7 @@ public class CPPBasicType implements ICPPBasicType {
private IASTExpression fExpression; private IASTExpression fExpression;
public CPPBasicType(Kind kind, int qualifiers, IASTExpression expression) { public CPPBasicType(Kind kind, int qualifiers, IASTExpression expression) {
if (kind == Kind.eUnspecified) { if (kind == Kind.eUnspecified && qualifiers != UNIQUE_TYPE_QUALIFIER) {
if ( (qualifiers & (IS_COMPLEX | IS_IMAGINARY)) != 0) { if ( (qualifiers & (IS_COMPLEX | IS_IMAGINARY)) != 0) {
fKind= Kind.eFloat; fKind= Kind.eFloat;
} else if ( (qualifiers & (IS_LONG | IS_SHORT | IS_SIGNED | IS_UNSIGNED | IS_LONG_LONG)) != 0 ) { } else if ( (qualifiers & (IS_LONG | IS_SHORT | IS_SIGNED | IS_UNSIGNED | IS_LONG_LONG)) != 0 ) {
@ -101,7 +101,7 @@ public class CPPBasicType implements ICPPBasicType {
if (object == this) if (object == this)
return true; return true;
if (fModifiers == -1) if (fModifiers == UNIQUE_TYPE_QUALIFIER)
return false; return false;
if (object instanceof ITypedef || object instanceof IIndexType) if (object instanceof ITypedef || object instanceof IIndexType)

View file

@ -39,7 +39,6 @@ import org.eclipse.cdt.core.dom.ast.IEnumeration;
import org.eclipse.cdt.core.dom.ast.IEnumerator; import org.eclipse.cdt.core.dom.ast.IEnumerator;
import org.eclipse.cdt.core.dom.ast.IFunction; import org.eclipse.cdt.core.dom.ast.IFunction;
import org.eclipse.cdt.core.dom.ast.IFunctionType; import org.eclipse.cdt.core.dom.ast.IFunctionType;
import org.eclipse.cdt.core.dom.ast.IParameter;
import org.eclipse.cdt.core.dom.ast.IPointerType; import org.eclipse.cdt.core.dom.ast.IPointerType;
import org.eclipse.cdt.core.dom.ast.IProblemBinding; import org.eclipse.cdt.core.dom.ast.IProblemBinding;
import org.eclipse.cdt.core.dom.ast.IQualifierType; import org.eclipse.cdt.core.dom.ast.IQualifierType;
@ -111,13 +110,11 @@ import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPDeferredClassInstance;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPFieldSpecialization; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPFieldSpecialization;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPFunctionInstance; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPFunctionInstance;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPFunctionSpecialization; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPFunctionSpecialization;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPFunctionTemplate;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPFunctionTemplateSpecialization; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPFunctionTemplateSpecialization;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPFunctionType; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPFunctionType;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPMethodInstance; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPMethodInstance;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPMethodSpecialization; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPMethodSpecialization;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPMethodTemplateSpecialization; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPMethodTemplateSpecialization;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPParameter;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPPointerToMemberType; 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.CPPPointerType;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPTemplateArgument; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPTemplateArgument;
@ -1794,9 +1791,8 @@ public class CPPTemplates {
* for each occurrence of that parameter in the function parameter list * for each occurrence of that parameter in the function parameter list
* @throws DOMException * @throws DOMException
*/ */
static private ICPPTemplateArgument[] createArgsForFunctionTemplateOrdering(ICPPFunctionTemplate template) static private ICPPTemplateArgument[] createArgsForFunctionTemplateOrdering(ICPPTemplateParameter[] paramList)
throws DOMException{ throws DOMException{
ICPPTemplateParameter[] paramList = template.getTemplateParameters();
int size = paramList.length; int size = paramList.length;
ICPPTemplateArgument[] args = new ICPPTemplateArgument[size]; ICPPTemplateArgument[] args = new ICPPTemplateArgument[size];
for (int i = 0; i < size; i++) { for (int i = 0; i < size; i++) {
@ -1812,51 +1808,54 @@ public class CPPTemplates {
static protected int orderTemplateFunctions(ICPPFunctionTemplate f1, ICPPFunctionTemplate f2) static protected int orderTemplateFunctions(ICPPFunctionTemplate f1, ICPPFunctionTemplate f2)
throws DOMException { throws DOMException {
// Using the transformed parameter list, perform argument deduction against the other // 14.5.5.2
// function template // A template is more specialized than another if and only if it is at least as specialized as the
CPPTemplateParameterMap m1= new CPPTemplateParameterMap(2);
CPPTemplateParameterMap m2= new CPPTemplateParameterMap(2);
ICPPTemplateArgument[] args = createArgsForFunctionTemplateOrdering(f1);
IBinding function = instantiateFunctionTemplate(f1, args);
if (function instanceof ICPPFunction)
if (!deduceTemplateParameterMapFromFunctionParameters(f2, ((ICPPFunction) function).getType().getParameterTypes(), m1))
m1= null;
args = createArgsForFunctionTemplateOrdering(f2);
function = instantiateFunctionTemplate(f2, args);
if (function instanceof ICPPFunction)
if (!deduceTemplateParameterMapFromFunctionParameters(f1, ((ICPPFunction) function).getType().getParameterTypes(), m2))
m2= null;
// The transformed template is at least as specialized as the other iff the deduction
// succeeds and the deduced parameter types are an exact match.
// A template is more specialized than another iff it is at least as specialized as the
// other template and that template is not at least as specialized as the first. // other template and that template is not at least as specialized as the first.
if (m1 == null) { boolean f1IsAtLeastAsSpecializedAsF2 = isAtLeastAsSpecializedAs(f1, f2);
if (m2 == null) boolean f2IsAtLeastAsSpecializedAsF1 = isAtLeastAsSpecializedAs(f2, f1);
return 0;
return -1;
}
if (m2 == null) if (f1IsAtLeastAsSpecializedAsF2 == f2IsAtLeastAsSpecializedAsF1)
return 0;
if (f1IsAtLeastAsSpecializedAsF2)
return 1; return 1;
// Count the number of cv-qualifications. The function with a lower number return -1;
// of cv-qualifications is more specialized. }
int d1 = 0;
for (ICPPTemplateArgument arg : m1.values()) { private static boolean isAtLeastAsSpecializedAs(ICPPFunctionTemplate f1, ICPPFunctionTemplate f2) throws DOMException {
if (arg.getTypeValue() instanceof IQualifierType) // 14.5.5.2
d1++; // Using the transformed parameter list, perform argument deduction against the other
// function template
// The transformed template is at least as specialized as the other if and only if the deduction
// succeeds and the deduced parameter types are an exact match.
ICPPTemplateArgument[] transferArgs = createArgsForFunctionTemplateOrdering(f1.getTemplateParameters());
IBinding transferredTemplate = instantiateFunctionTemplate(f1, transferArgs);
if (!(transferredTemplate instanceof ICPPFunction))
return false;
CPPTemplateParameterMap map= new CPPTemplateParameterMap(2);
final IType[] transferredParameterTypes = ((ICPPFunction) transferredTemplate).getType().getParameterTypes();
if (!deduceTemplateParameterMapFromFunctionParameters(f2, transferredParameterTypes, map))
return false;
final ICPPTemplateParameter[] tmplParams = f2.getTemplateParameters();
for (ICPPTemplateParameter tmplParam : tmplParams) {
ICPPTemplateArgument deducedArg= map.getArgument(tmplParam);
if (deducedArg == null)
return false;
} }
int d2 = 0;
for (ICPPTemplateArgument arg : m2.values()) { // length can be different in case of varargs or default arguments
if (arg.getTypeValue() instanceof IQualifierType) { IType[] params= f2.getType().getParameterTypes();
d2++; final int len= Math.min(params.length, transferredParameterTypes.length);
} for (int i = 0; i <len; i++) {
IType instantiated= instantiateType(params[i], map, null);
// we need to be able to compare class instances from different caches here
if (!instantiated.isSameType(transferredParameterTypes[i]))
return false;
} }
return d1 - d2; return true;
} }
private static ICPPClassTemplatePartialSpecialization findPartialSpecialization(ICPPClassTemplate ct, ICPPTemplateArgument[] args) throws DOMException { private static ICPPClassTemplatePartialSpecialization findPartialSpecialization(ICPPClassTemplate ct, ICPPTemplateArgument[] args) throws DOMException {
@ -1930,71 +1929,62 @@ public class CPPTemplates {
return -1; return -1;
} }
//to order class template specializations, we need to transform them into function templates // we avoid the transformation to function templates, of which the one parameter
ICPPFunctionTemplate template1 = classTemplateSpecializationToFunctionTemplate(spec1); // will be used in the end.
ICPPFunctionTemplate template2 = classTemplateSpecializationToFunctionTemplate(spec2);
if (template1 == null) { // 14.5.5.2
if (template2 == null) // A template is more specialized than another if and only if it is at least as specialized as the
return 0; // other template and that template is not at least as specialized as the first.
boolean f1IsAtLeastAsSpecializedAsF2 = isAtLeastAsSpecializedAs(spec1, spec2);
boolean f2IsAtLeastAsSpecializedAsF1 = isAtLeastAsSpecializedAs(spec2, spec1);
if (f1IsAtLeastAsSpecializedAsF2 == f2IsAtLeastAsSpecializedAsF1)
return 0;
if (f1IsAtLeastAsSpecializedAsF2)
return 1; return 1;
}
if (template2 == null)
return -1;
return orderTemplateFunctions(template1, template2); return -1;
} }
public static final class CPPImplicitFunctionTemplate extends CPPFunctionTemplate { private static boolean isAtLeastAsSpecializedAs(ICPPClassTemplatePartialSpecialization f1, ICPPClassTemplatePartialSpecialization f2) throws DOMException {
IParameter[] functionParameters = null; // 14.5.5.2
ICPPTemplateParameter[] templateParameters = null; // Using the transformed parameter list, perform argument deduction against the other
// function template
// The transformed template is at least as specialized as the other if and only if the deduction
// succeeds and the deduced parameter types are an exact match.
final ICPPTemplateParameter[] tpars1 = f1.getTemplateParameters();
final ICPPTemplateParameter[] tpars2 = f2.getTemplateParameters();
final ICPPTemplateArgument[] targs1 = f1.getTemplateArguments();
final ICPPTemplateArgument[] targs2 = f2.getTemplateArguments();
if (targs1.length != targs2.length)
return false;
public CPPImplicitFunctionTemplate(ICPPTemplateParameter[] templateParameters, IParameter[] functionParameters) { // transfer arguments of specialization 1
super(null); final ICPPTemplateArgument[] helperArgs = createArgsForFunctionTemplateOrdering(tpars1);
this.functionParameters = functionParameters; final CPPTemplateParameterMap transferMap= new CPPTemplateParameterMap(5);
this.templateParameters = templateParameters; for (int i = 0; i < tpars1.length; i++) {
transferMap.put(tpars1[i], helperArgs[i]);
} }
@Override final ICPPTemplateArgument[] transferredArgs1 = instantiateArguments(targs1, transferMap, null);
public IParameter[] getParameters() {
return functionParameters;
}
@Override
public ICPPTemplateParameter[] getTemplateParameters() {
return templateParameters;
}
@Override
public IScope getScope() {
return null;
}
@Override
public ICPPFunctionType getType() {
if (type == null) {
type = CPPVisitor.createImplicitFunctionType(new CPPBasicType(Kind.eVoid, 0), functionParameters, false, false);
}
return type;
}
}
/**
* transform the class template to a function template as described in the spec
* 14.5.4.2-1
* @param template
* @return IParameterizedSymbol
* the function template has the same template parameters as the partial specialization and
* has a single function parameter whose type is a class template specialization with the template
* arguments of the partial specialization
*/
static private ICPPFunctionTemplate classTemplateSpecializationToFunctionTemplate(ICPPClassTemplatePartialSpecialization specialization) {
try {
ICPPTemplateArgument[] args= specialization.getTemplateArguments();
IBinding paramType = deferredInstance(specialization, args);
if (!(paramType instanceof IType))
return null;
IParameter[] functionParameters = new IParameter[] { new CPPParameter((IType) paramType, 0) }; // deduce arguments for specialization 2
final CPPTemplateParameterMap deductionMap= new CPPTemplateParameterMap(2);
return new CPPImplicitFunctionTemplate(specialization.getTemplateParameters(), functionParameters); if (!deduceTemplateParameterMap(targs2, transferredArgs1, deductionMap))
} catch (DOMException e) { return false;
return null; 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);
if (!transferredArg2.isSameValue(transferredArgs1[i]))
return false;
}
return true;
} }
static private boolean isValidType(IType t) { static private boolean isValidType(IType t) {