1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-06-07 17:56:01 +02:00

Bug 326492: Overloaded function-sets in instantiation of function templates.

This commit is contained in:
Markus Schorn 2010-09-29 12:54:36 +00:00
parent ef4a1226fe
commit bbf5a39ad8
8 changed files with 180 additions and 98 deletions

View file

@ -648,7 +648,7 @@ public class AST2BaseTest extends BaseTestCase {
Iterator i = col.nameList.iterator();
while (i.hasNext()) {
IASTName n = (IASTName) i.next();
assertFalse(n.resolveBinding() instanceof IProblemBinding);
assertFalse("ProblemBinding for " + n.getRawSignature(), n.resolveBinding() instanceof IProblemBinding);
}
}

View file

@ -5154,4 +5154,36 @@ public class AST2TemplateTests extends AST2BaseTest {
public void testAdressOfUniqueTemplateInst_Bug326076() throws Exception {
parseAndCheckBindings();
}
// template <typename T> void f(T (*)(int), char);
// template <typename T> void f(int (*)(T), int);
// template <typename T> void f(T, int);
//
// int g(char);
// void g(int);
//
// void b() {
// f(g, '1');
// f(g, 1);
// }
public void testInstantiationOfFunctionTemplateWithOverloadedFunctionSetArgument_Bug326492() throws Exception {
String code= getAboveComment();
BindingAssertionHelper bh= new BindingAssertionHelper(code, true);
ICPPFunctionTemplate f1= bh.assertNonProblem("f(T (*)(int), char)", 1);
ICPPFunctionTemplate f2= bh.assertNonProblem("f(int (*)(T), int)", 1);
IFunction g1= bh.assertNonProblem("g(char)", 1);
IFunction g2= bh.assertNonProblem("g(int)", 1);
ICPPTemplateInstance t;
t= bh.assertNonProblem("f(g, '1')", 1);
assertSame(f1, t.getTemplateDefinition());
t= bh.assertNonProblem("f(g, 1)", 1);
assertSame(f2, t.getTemplateDefinition());
ICPPFunction g;
g= bh.assertNonProblem("g, '1')", 1);
assertSame(g2, g);
g= bh.assertNonProblem("g, 1)", 1);
assertSame(g1, g);
}
}

View file

@ -5915,12 +5915,13 @@ public class AST2Tests extends AST2BaseTest {
final Runtime runtime = Runtime.getRuntime();
long mem= runtime.totalMemory()-runtime.freeMemory();
long newMem= mem;
int i=0;
do {
Thread.sleep(50);
System.gc();
mem= newMem;
newMem= runtime.totalMemory()-runtime.freeMemory();
} while (newMem < mem);
} while (newMem < mem && ++i<5);
return mem;
}

View file

@ -22,6 +22,7 @@ import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.ExpressionT
import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
@ -2295,8 +2296,9 @@ public class CPPSemantics {
// Reduce our set of candidate functions to only those who have the right number of parameters
final IType[] argTypes = data.getFunctionArgumentTypes();
ICPPFunction[] tmp= selectByArgumentCount(data, fns);
tmp= CPPTemplates.instantiateFunctionTemplates(tmp, argTypes, data.getFunctionArgumentValueCategories(),
data.astName, data.argsContainImpliedObject);
tmp= CPPTemplates.instantiateForFunctionCall(data.astName, tmp,
Arrays.asList(argTypes),
Arrays.asList(data.getFunctionArgumentValueCategories()), data.argsContainImpliedObject);
if (tmp.length == 0 || tmp[0] == null)
return new ProblemBinding(data.astName, IProblemBinding.SEMANTIC_NAME_NOT_FOUND, fns);
@ -2437,7 +2439,7 @@ public class CPPSemantics {
}
if (result instanceof ICPPFunctionTemplate)
return CPPTemplates.instantiateFunctionTemplate((ICPPFunctionTemplate) result, null, name);
return CPPTemplates.instantiateForAddressOfFunction((ICPPFunctionTemplate) result, null, name);
return result;
}
@ -2452,8 +2454,10 @@ public class CPPSemantics {
private static IBinding resolveFunctionDeclaration(LookupData data, ICPPFunction[] fns) throws DOMException {
if (data.forExplicitFunctionSpecialization()) {
fns= CPPTemplates.instantiateFunctionTemplates(fns, data.getFunctionArgumentTypes(),
data.getFunctionArgumentValueCategories(), data.astName, data.argsContainImpliedObject);
fns = CPPTemplates.instantiateForFunctionCall(data.astName,
fns,
Arrays.asList(data.getFunctionArgumentTypes()), Arrays.asList(data.getFunctionArgumentValueCategories()),
data.argsContainImpliedObject);
}
int argCount = data.getFunctionArgumentCount();
@ -2812,7 +2816,7 @@ public class CPPSemantics {
try {
if (fn instanceof ICPPFunctionTemplate) {
final ICPPFunctionTemplate template = (ICPPFunctionTemplate) fn;
ICPPFunction inst= CPPTemplates.instantiateFunctionTemplate(template, (ICPPFunctionType) targetType, name);
ICPPFunction inst= CPPTemplates.instantiateForAddressOfFunction(template, (ICPPFunctionType) targetType, name);
if (inst != null) {
int cmp= -1;
if (result != null) {

View file

@ -16,8 +16,12 @@ package org.eclipse.cdt.internal.core.dom.parser.cpp.semantics;
import static org.eclipse.cdt.core.dom.ast.IASTExpression.ValueCategory.LVALUE;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.eclipse.cdt.core.dom.IName;
import org.eclipse.cdt.core.dom.ast.ASTTypeUtil;
@ -1538,97 +1542,126 @@ public class CPPTemplates {
return result;
}
static ICPPFunction[] instantiateFunctionTemplates(ICPPFunction[] fns, IType[] allFnArgs,
ValueCategory[] allValueCategories, IASTName name, boolean argsContainImpliedObject) {
boolean requireTemplate= false;
if (name != null) {
if (name.getPropertyInParent() == ICPPASTTemplateId.TEMPLATE_NAME) {
static ICPPFunction[] instantiateForFunctionCall(IASTName name, ICPPFunction[] fns,
List<IType> fnArgs, List<ValueCategory> argCats, boolean withImpliedObjectArg) {
if (name != null && name.getPropertyInParent() == ICPPASTTemplateId.TEMPLATE_NAME) {
name= (IASTName) name.getParent();
requireTemplate= true;
} else if (name instanceof ICPPASTTemplateId) {
requireTemplate= true;
}
}
IType[] reducedFnArgs= null;
ValueCategory[] reducedValueCategories= null;
ICPPTemplateArgument[] tmplArgs= null;
ICPPFunction[] result= fns;
int idx= 0;
for (int i = 0; i < fns.length; i++) {
final ICPPFunction func = fns[i];
ICPPFunction rf= null;
// Extract template arguments.
ICPPTemplateArgument[] tmplArgs= ICPPTemplateArgument.EMPTY_ARGUMENTS;
boolean requireTemplate= name instanceof ICPPASTTemplateId;
boolean haveTemplate= false;
for (final ICPPFunction func : fns) {
if (func instanceof ICPPConstructor || (func instanceof ICPPMethod && ((ICPPMethod) func).isDestructor()))
requireTemplate= false;
if (func instanceof ICPPFunctionTemplate) {
ICPPFunctionTemplate template= (ICPPFunctionTemplate) func;
final IType[] fnArgs;
final ValueCategory[] valueCategories;
if (argsContainImpliedObject && template instanceof ICPPMethod) {
if (reducedValueCategories == null) {
if (allFnArgs != null && allFnArgs.length > 0) {
reducedFnArgs= ArrayUtil.removeFirst(allFnArgs);
}
if (allValueCategories == null || allValueCategories.length == 0) {
reducedValueCategories= new ValueCategory[0];
} else {
reducedValueCategories= ArrayUtil.removeFirst(allValueCategories);
}
}
fnArgs= reducedFnArgs;
valueCategories= reducedValueCategories;
} else {
fnArgs= allFnArgs;
valueCategories= allValueCategories;
}
// extract template arguments and parameter types.
if (tmplArgs == null || fnArgs == null) {
tmplArgs = ICPPTemplateArgument.EMPTY_ARGUMENTS;
try {
if (fnArgs == null || containsDependentType(fnArgs)) {
if (containsDependentType(fnArgs))
return new ICPPFunction[] {CPPUnknownFunction.createForSample(template)};
}
if (name instanceof ICPPASTTemplateId && !(template instanceof ICPPConstructor)) {
if (requireTemplate) {
tmplArgs = createTemplateArgumentArray((ICPPASTTemplateId) name);
if (hasDependentArgument(tmplArgs)) {
if (hasDependentArgument(tmplArgs))
return new ICPPFunction[] {CPPUnknownFunction.createForSample(template)};
}
}
} catch (DOMException e) {
return NO_FUNCTIONS;
}
}
CPPTemplateParameterMap map= new CPPTemplateParameterMap(fnArgs.length);
try {
ICPPTemplateArgument[] args= TemplateArgumentDeduction.deduceForFunctionCall(template, tmplArgs, fnArgs, valueCategories, map);
if (args != null) {
IBinding instance= instantiateFunctionTemplate(template, args, map);
if (instance instanceof ICPPFunction) {
rf= (ICPPFunction) instance;
haveTemplate= true;
break;
}
}
} catch (DOMException e) {
// try next candidate
if (!haveTemplate && !requireTemplate)
return fns;
final List<ICPPFunction> result= new ArrayList<ICPPFunction>(fns.length);
final List<List<IType>> crossProduct= expandOverloadedSets(fnArgs);
for (ICPPFunction fn : fns) {
if (fn != null) {
if (fn instanceof ICPPFunctionTemplate) {
ICPPFunctionTemplate fnTmpl= (ICPPFunctionTemplate) fn;
for (List<IType> args : crossProduct) {
ICPPFunction inst = instantiateForFunctionCall(fnTmpl, tmplArgs, args, argCats, withImpliedObjectArg);
if (inst != null)
result.add(inst);
}
} else if (!requireTemplate
|| (func instanceof ICPPConstructor) || (func instanceof ICPPUnknownBinding)
|| (func instanceof ICPPMethod && ((ICPPMethod) func).isDestructor())) {
rf= func;
} else if (!requireTemplate || fn instanceof ICPPUnknownBinding) {
result.add(fn);
}
if (rf != func || result != fns) {
if (result == fns) {
result= new ICPPFunction[fns.length-(i-idx)];
System.arraycopy(fns, 0, result, 0, idx);
}
if (rf != null)
result[idx]= rf;
}
if (rf != null)
idx++;
return result.toArray(new ICPPFunction[result.size()]);
}
private static List<List<IType>> expandOverloadedSets(List<IType> fnArgs) {
List<List<IType>> result= Collections.singletonList(fnArgs);
int i= 0;
for (IType arg : fnArgs) {
if (arg instanceof FunctionSetType) {
Collection<ICPPFunctionType> targetTypes= getFunctionTypes((FunctionSetType) arg);
if (targetTypes.isEmpty())
return Collections.emptyList();
List<List<IType>> expanded= new ArrayList<List<IType>>(targetTypes.size() * result.size());
for (IType targetType : targetTypes) {
for (List<IType> orig : result) {
ArrayList<IType> copy = new ArrayList<IType>(orig);
copy.set(i, new CPPPointerType(targetType));
expanded.add(copy);
}
}
result= expanded;
}
i++;
}
return result;
}
static protected void instantiateConversionTemplates(IFunction[] functions, IType conversionType) {
private static Collection<ICPPFunctionType> getFunctionTypes(FunctionSetType fst) {
final ICPPFunction[] functionSet = fst.getFunctionSet();
Set<String> handled= new HashSet<String>();
Collection<ICPPFunctionType> result= new ArrayList<ICPPFunctionType>(functionSet.length);
for (ICPPFunction f : functionSet) {
if (! (f instanceof ICPPFunctionTemplate)) {
try {
ICPPFunctionType t= f.getType();
if (handled.add(ASTTypeUtil.getType(t, true)))
result.add(t);
} catch (DOMException e) {
}
}
}
return result;
}
private static ICPPFunction instantiateForFunctionCall(ICPPFunctionTemplate template,
ICPPTemplateArgument[] tmplArgs, List<IType> fnArgs, List<ValueCategory> argCats,
boolean withImpliedObjectArg) {
if (withImpliedObjectArg && template instanceof ICPPMethod) {
fnArgs= fnArgs.subList(1, fnArgs.size());
argCats= argCats.subList(1, argCats.size());
}
CPPTemplateParameterMap map= new CPPTemplateParameterMap(fnArgs.size());
try {
ICPPTemplateArgument[] args= TemplateArgumentDeduction.deduceForFunctionCall(template, tmplArgs, fnArgs, argCats, map);
if (args != null) {
IBinding instance= instantiateFunctionTemplate(template, args, map);
if (instance instanceof ICPPFunction) {
return (ICPPFunction) instance;
}
}
} catch (DOMException e) {
}
return null;
}
static void instantiateConversionTemplates(IFunction[] functions, IType conversionType) {
boolean checkedForDependentType= false;
for (int i = 0; i < functions.length; i++) {
IFunction func = functions[i];
@ -1667,7 +1700,7 @@ public class CPPTemplates {
/**
* 14.8.2.2 Deducing template arguments taking the address of a function template [temp.deduct.funcaddr]
*/
static protected ICPPFunction instantiateFunctionTemplate(ICPPFunctionTemplate template, IFunctionType target, IASTName name) {
static ICPPFunction instantiateForAddressOfFunction(ICPPFunctionTemplate template, IFunctionType target, IASTName name) {
if (name.getPropertyInParent() == ICPPASTTemplateId.TEMPLATE_NAME) {
name= (IASTName) name.getParent();
}
@ -1728,7 +1761,7 @@ public class CPPTemplates {
return args;
}
static protected int orderTemplateFunctions(ICPPFunctionTemplate f1, ICPPFunctionTemplate f2)
static int orderTemplateFunctions(ICPPFunctionTemplate f1, ICPPFunctionTemplate f2)
throws DOMException {
// 14.5.5.2
// A template is more specialized than another if and only if it is at least as specialized as the
@ -1765,7 +1798,7 @@ public class CPPTemplates {
map= new CPPTemplateParameterMap(2);
final IType[] transferredParameterTypes = ((ICPPFunction) transferredTemplate).getType().getParameterTypes();
if (!TemplateArgumentDeduction.deduceFromFunctionArgs(f2, transferredParameterTypes, null, map, true))
if (!TemplateArgumentDeduction.deduceFromFunctionArgs(f2, Arrays.asList(transferredParameterTypes), null, map, true))
return false;
final int last = tmplParams1.length -1;
@ -1912,7 +1945,7 @@ public class CPPTemplates {
return arg != null && isValidType(arg.isTypeValue() ? arg.getTypeValue() : arg.getTypeOfNonTypeValue());
}
static protected ICPPTemplateArgument matchTemplateParameterAndArgument(ICPPTemplateParameter param,
static ICPPTemplateArgument matchTemplateParameterAndArgument(ICPPTemplateParameter param,
ICPPTemplateArgument arg, CPPTemplateParameterMap map) {
if (arg == null || !isValidType(arg.getTypeValue())) {
return null;
@ -2079,6 +2112,14 @@ public class CPPTemplates {
return Value.isDependentValue(arg.getNonTypeValue());
}
public static boolean containsDependentType(List<IType> ts) {
for (IType t : ts) {
if (isDependentType(t))
return true;
}
return false;
}
public static boolean containsDependentType(IType[] ts) {
for (IType t : ts) {
if (isDependentType(t))

View file

@ -16,6 +16,7 @@ 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.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
@ -1819,8 +1820,8 @@ public class CPPVisitor extends ASTQueries {
}
ICPPFunctionTemplate template = new AutoTypeResolver(type);
CPPTemplateParameterMap paramMap = new CPPTemplateParameterMap(1);
TemplateArgumentDeduction.deduceFromFunctionArgs(template, new IType[] { initType },
new ValueCategory[] { valueCat }, paramMap, false);
TemplateArgumentDeduction.deduceFromFunctionArgs(template, Collections.singletonList(initType),
Collections.singletonList(valueCat), paramMap, false);
ICPPTemplateArgument argument = paramMap.getArgument(0, 0);
if (argument == null) {
return null;

View file

@ -19,6 +19,8 @@ import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CVQualifier
import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.ExpressionTypes.valueCategoryFromReturnType;
import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.*;
import java.util.Collections;
import org.eclipse.cdt.core.dom.ast.DOMException;
import org.eclipse.cdt.core.dom.ast.IASTExpression;
import org.eclipse.cdt.core.dom.ast.IASTExpression.ValueCategory;
@ -668,7 +670,8 @@ public class Conversions {
FunctionCost cost1= null;
Cost cost2= null;
ICPPFunction[] ctors= t.getConstructors();
ctors= CPPTemplates.instantiateFunctionTemplates(ctors, new IType[]{source}, new ValueCategory[] {valueCat}, null, false);
ctors = CPPTemplates.instantiateForFunctionCall(null, ctors,
Collections.singletonList(source), Collections.singletonList(valueCat), false);
for (ICPPFunction f : ctors) {
if (!(f instanceof ICPPConstructor) || f instanceof IProblemBinding)

View file

@ -61,7 +61,7 @@ public class TemplateArgumentDeduction {
* 14.8.2.1
*/
static ICPPTemplateArgument[] deduceForFunctionCall(ICPPFunctionTemplate template,
ICPPTemplateArgument[] tmplArgs, IType[] fnArgs, ValueCategory[] argIsLValue, CPPTemplateParameterMap map)
ICPPTemplateArgument[] tmplArgs, List<IType> fnArgs, List<ValueCategory> argIsLValue, CPPTemplateParameterMap map)
throws DOMException {
final ICPPTemplateParameter[] tmplParams = template.getTemplateParameters();
final int numTmplParams = tmplParams.length;
@ -235,7 +235,7 @@ public class TemplateArgumentDeduction {
* Deduces the mapping for the template parameters from the function parameters,
* returns <code>false</code> if there is no mapping.
*/
static boolean deduceFromFunctionArgs(ICPPFunctionTemplate template, IType[] fnArgs, ValueCategory[] argIsLValue,
static boolean deduceFromFunctionArgs(ICPPFunctionTemplate template, List<IType> fnArgs, List<ValueCategory> argCats,
CPPTemplateParameterMap map, boolean checkExactMatch) {
try {
IType[] fnPars = template.getType().getParameterTypes();
@ -246,7 +246,7 @@ public class TemplateArgumentDeduction {
final ICPPTemplateParameter[] tmplPars = template.getTemplateParameters();
TemplateArgumentDeduction deduct= new TemplateArgumentDeduction(tmplPars, map, new CPPTemplateParameterMap(fnParCount), 0);
IType fnParPack= null;
for (int j= 0; j < fnArgs.length; j++) {
for (int j= 0; j < fnArgs.size(); j++) {
IType par;
if (fnParPack != null) {
par= fnParPack;
@ -258,7 +258,7 @@ public class TemplateArgumentDeduction {
continue; // non-deduced context
par= fnParPack= ((ICPPParameterPackType) par).getType();
deduct= new TemplateArgumentDeduction(deduct, fnArgs.length - j);
deduct= new TemplateArgumentDeduction(deduct, fnArgs.size() - j);
}
} else {
break;
@ -270,7 +270,7 @@ public class TemplateArgumentDeduction {
boolean isDependentPar= CPPTemplates.isDependentType(par);
if (checkExactMatch || isDependentPar) {
IType arg = fnArgs[j];
IType arg = fnArgs.get(j);
par= SemanticUtil.getNestedType(par, SemanticUtil.TDEF); // adjustParameterType preserves typedefs
// C++0x: 14.9.2.1-1
@ -293,7 +293,7 @@ public class TemplateArgumentDeduction {
}
// 14.8.2.1-2
ValueCategory cat= argIsLValue != null ? argIsLValue[j] : LVALUE;
ValueCategory cat= argCats != null ? argCats.get(j) : LVALUE;
if (!deduceFromFunctionArg(par, arg, cat, checkExactMatch, isDependentPar, deduct)) {
return false;
}