1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-08-11 10:15:39 +02:00

Constructor template in implicit conversion sequence, bug 264314.

This commit is contained in:
Markus Schorn 2009-02-10 12:46:46 +00:00
parent 59bc9825a4
commit 86041e3f39
8 changed files with 122 additions and 141 deletions

View file

@ -6719,4 +6719,20 @@ public class AST2CPPTests extends AST2BaseTest {
String code= getAboveComment(); String code= getAboveComment();
parseAndCheckBindings(code, ParserLanguage.CPP); parseAndCheckBindings(code, ParserLanguage.CPP);
} }
// template<typename IteratorT> class range {
// public:
// template<class Range> range(const Range& r) {}
// };
// void onRange(const range<const char*>& r) {}
// void test() {
// range<char*> ir(0);
// onRange(ir);
// }
public void testConstructorTemplateInImplicitConversion_264314() throws Exception {
final String code = getAboveComment();
BindingAssertionHelper ba= new BindingAssertionHelper(code, true);
ba.assertNonProblem("onRange(ir)", 7);
parseAndCheckBindings(code, ParserLanguage.CPP);
}
} }

View file

@ -162,8 +162,8 @@ public class CPPASTUnaryExpression extends ASTNode implements
} catch (DOMException e) { } catch (DOMException e) {
return e.getProblem(); return e.getProblem();
} }
return new CPPPointerToMemberType(type, (ICPPClassType) nestedType, return new CPPPointerToMemberType(type, nestedType, thisType.isConst(), thisType
thisType.isConst(), thisType.isVolatile()); .isVolatile());
} }
} }
return new CPPPointerType(type); return new CPPPointerType(type);

View file

@ -1651,13 +1651,10 @@ public class CPPSemantics {
final boolean indexBased= data.tu != null && data.tu.getIndex() != null; final boolean indexBased= data.tu != null && data.tu.getIndex() != null;
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
ObjectSet<IFunction> fns= ObjectSet.EMPTY_SET; ObjectSet<IFunction> fns= ObjectSet.EMPTY_SET;
@SuppressWarnings("unchecked")
ObjectSet<IFunction> templateFns= ObjectSet.EMPTY_SET;
IBinding type = null; IBinding type = null;
IBinding obj = null; IBinding obj = null;
IBinding temp = null; IBinding temp = null;
boolean fnsFromAST= false; boolean fnsFromAST= false;
boolean fnTmplsFromAST= false;
Object[] items = (Object[]) data.foundItems; Object[] items = (Object[]) data.foundItems;
for (int i = 0; i < items.length && items[i] != null; i++) { for (int i = 0; i < items.length && items[i] != null; i++) {
@ -1713,22 +1710,6 @@ public class CPPSemantics {
} }
IFunction function= (IFunction) temp; IFunction function= (IFunction) temp;
if (function instanceof ICPPFunctionTemplate) {
if (templateFns == ObjectSet.EMPTY_SET)
templateFns = new ObjectSet<IFunction>(2);
if (isFromIndex(function)) {
// accept bindings from index only, in case we have none in the AST
if (!fnTmplsFromAST) {
templateFns.put(function);
}
} else {
if (!fnTmplsFromAST) {
templateFns.clear();
fnTmplsFromAST= true;
}
templateFns.put(function);
}
} else {
if (fns == ObjectSet.EMPTY_SET) if (fns == ObjectSet.EMPTY_SET)
fns = new ObjectSet<IFunction>(2); fns = new ObjectSet<IFunction>(2);
if (isFromIndex(function)) { if (isFromIndex(function)) {
@ -1743,7 +1724,6 @@ public class CPPSemantics {
} }
fns.put(function); fns.put(function);
} }
}
} else if (temp instanceof IType) { } else if (temp instanceof IType) {
// specializations are selected during instantiation // specializations are selected during instantiation
if (temp instanceof ICPPClassTemplatePartialSpecialization) if (temp instanceof ICPPClassTemplatePartialSpecialization)
@ -1804,47 +1784,32 @@ public class CPPSemantics {
// if (fns == null) return type; // if (fns == null) return type;
bindings = (IBinding[]) ArrayUtil.append(IBinding.class, bindings, type); bindings = (IBinding[]) ArrayUtil.append(IBinding.class, bindings, type);
bindings = (IBinding[]) ArrayUtil.addAll(IBinding.class, bindings, fns.keyArray()); bindings = (IBinding[]) ArrayUtil.addAll(IBinding.class, bindings, fns.keyArray());
bindings = (IBinding[]) ArrayUtil.addAll(IBinding.class, bindings, templateFns.keyArray());
} }
bindings = (IBinding[]) ArrayUtil.trim(IBinding.class, bindings); bindings = (IBinding[]) ArrayUtil.trim(IBinding.class, bindings);
ICPPUsingDeclaration composite = new CPPUsingDeclaration(data.astName, bindings); ICPPUsingDeclaration composite = new CPPUsingDeclaration(data.astName, bindings);
return composite; return composite;
} }
int numTemplateFns = templateFns.size(); if (data.typesOnly) {
if (numTemplateFns > 0) { if (type != null)
if (data.functionParameters != null &&
(!data.forFunctionDeclaration() || data.forExplicitFunctionSpecialization())) {
IFunction[] fs = CPPTemplates.selectTemplateFunctions(templateFns, data.functionParameters, data.astName);
if (fs != null && fs.length > 0) {
if (fns == ObjectSet.EMPTY_SET)
fns = new ObjectSet<IFunction>(fs.length);
fns.addAll(fs);
}
} else {
if (fns == ObjectSet.EMPTY_SET)
fns = templateFns;
else
fns.addAll(templateFns);
}
}
int numFns = fns.size();
if (type != null) {
if (data.typesOnly || (obj == null && numFns == 0))
return type; return type;
if (obj instanceof ICPPNamespace)
return obj;
return null;
} }
int numFns = fns.size();
if (numFns > 0) { if (numFns > 0) {
if (obj != null) if (obj != null)
return new ProblemBinding(data.astName, IProblemBinding.SEMANTIC_AMBIGUOUS_LOOKUP); return new ProblemBinding(data.astName, IProblemBinding.SEMANTIC_AMBIGUOUS_LOOKUP);
return resolveFunction(data, fns.keyArray(IFunction.class)); return resolveFunction(data, fns.keyArray(IFunction.class), true);
} }
if (data.typesOnly && obj instanceof ICPPNamespace == false) { if (obj != null) {
return null;
}
return obj; return obj;
} }
return type;
}
private static boolean isFromIndex(IBinding binding) { private static boolean isFromIndex(IBinding binding) {
if (binding instanceof IIndexBinding) { if (binding instanceof IIndexBinding) {
@ -1878,8 +1843,10 @@ public class CPPSemantics {
// Trim the list down to the set of viable functions // Trim the list down to the set of viable functions
IFunction function = null; IFunction function = null;
int size = functions.length; int size = functions.length;
for (int i = 0; i < size && functions[i] != null; i++) { for (int i = 0; i < size; i++) {
function = (IFunction) functions[i]; function = (IFunction) functions[i];
if (function == null)
continue;
if (function instanceof IProblemBinding) { if (function instanceof IProblemBinding) {
functions[i]= null; functions[i]= null;
continue; continue;
@ -1978,7 +1945,7 @@ public class CPPSemantics {
return result; return result;
} }
static IBinding resolveFunction(LookupData data, IFunction[] fns) throws DOMException { static IBinding resolveFunction(LookupData data, IFunction[] fns, boolean allowUDC) throws DOMException {
fns= (IFunction[]) ArrayUtil.trim(IFunction.class, fns); fns= (IFunction[]) ArrayUtil.trim(IFunction.class, fns);
if (fns == null || fns.length == 0) if (fns == null || fns.length == 0)
return null; return null;
@ -1987,14 +1954,19 @@ public class CPPSemantics {
return new CPPUsingDeclaration(data.astName, fns); return new CPPUsingDeclaration(data.astName, fns);
} }
if (data.astName instanceof ICPPASTConversionName) {
return resolveUserDefinedConversion((ICPPASTConversionName) data.astName, fns);
}
// We don't have any arguments with which to resolve the function // We don't have any arguments with which to resolve the function
if (data.functionParameters == null) { if (data.functionParameters == null) {
return resolveTargetedFunction(data, fns); return resolveTargetedFunction(data, fns);
} }
if (!data.forFunctionDeclaration() || data.forExplicitFunctionSpecialization()) {
CPPTemplates.instantiateFunctionTemplates(fns, data.functionParameters, data.astName);
}
if (data.astName instanceof ICPPASTConversionName) {
return resolveUserDefinedConversion((ICPPASTConversionName) data.astName, fns);
}
// Reduce our set of candidate functions to only those who have the right number of parameters // Reduce our set of candidate functions to only those who have the right number of parameters
reduceToViable(data, fns); reduceToViable(data, fns);
@ -2060,7 +2032,6 @@ public class CPPSemantics {
currFnCost= new Cost[sourceLen]; currFnCost= new Cost[sourceLen];
} }
comparison = 0;
boolean varArgs = false; boolean varArgs = false;
boolean isImpliedObject= false; boolean isImpliedObject= false;
for (int j = 0; j < sourceLen; j++) { for (int j = 0; j < sourceLen; j++) {
@ -2097,8 +2068,8 @@ public class CPPSemantics {
cost = new Cost(source, target); cost = new Cost(source, target);
cost.rank = Cost.IDENTITY_RANK; // exact match, no cost cost.rank = Cost.IDENTITY_RANK; // exact match, no cost
} else { } else {
cost= Conversions.checkImplicitConversionSequence(!data.forUserDefinedConversion, cost= Conversions.checkImplicitConversionSequence(sourceExp,
sourceExp, source, target, isImpliedObject); source, target, allowUDC, isImpliedObject);
} }
if (cost.rank < 0) if (cost.rank < 0)

View file

@ -85,7 +85,6 @@ import org.eclipse.cdt.core.parser.util.ArrayUtil;
import org.eclipse.cdt.core.parser.util.CharArraySet; import org.eclipse.cdt.core.parser.util.CharArraySet;
import org.eclipse.cdt.core.parser.util.CharArrayUtils; import org.eclipse.cdt.core.parser.util.CharArrayUtils;
import org.eclipse.cdt.core.parser.util.ObjectMap; import org.eclipse.cdt.core.parser.util.ObjectMap;
import org.eclipse.cdt.core.parser.util.ObjectSet;
import org.eclipse.cdt.internal.core.dom.parser.ASTAmbiguousNode; import org.eclipse.cdt.internal.core.dom.parser.ASTAmbiguousNode;
import org.eclipse.cdt.internal.core.dom.parser.ASTQueries; import org.eclipse.cdt.internal.core.dom.parser.ASTQueries;
import org.eclipse.cdt.internal.core.dom.parser.IASTInternalScope; import org.eclipse.cdt.internal.core.dom.parser.IASTInternalScope;
@ -1332,50 +1331,50 @@ public class CPPTemplates {
return result; return result;
} }
static protected IFunction[] selectTemplateFunctions(ObjectSet<IFunction> templates, static protected void instantiateFunctionTemplates(IFunction[] functions,
Object[] functionArguments, IASTName name) { Object[] functionArguments, IASTName name) {
ICPPTemplateArgument[] templateArguments= null;
IType[] fnArgs= null;
for (int i = 0; i < functions.length; i++) {
IFunction func = functions[i];
if (func instanceof ICPPFunctionTemplate) {
ICPPFunctionTemplate template= (ICPPFunctionTemplate) func;
functions[i]= null;
if (templates == null || templates.size() == 0) // extract template arguments and parameter types.
return null; if (templateArguments == null || fnArgs == null) {
templateArguments = ICPPTemplateArgument.EMPTY_ARGUMENTS;
ICPPTemplateArgument[] templateArguments = ICPPTemplateArgument.EMPTY_ARGUMENTS; fnArgs= createTypeArray(functionArguments);
final IType[] fnArgs= createTypeArray(functionArguments);
try { try {
if (containsDependentType(fnArgs)) if (containsDependentType(fnArgs)) {
return new IFunction[] {CPPUnknownFunction.createForSample(templates.keyAt(0), name)}; functions[i]= CPPUnknownFunction.createForSample(template, name);
return;
if (name instanceof ICPPASTTemplateId) { }
if (name instanceof ICPPASTTemplateId && !(template instanceof ICPPConstructor)) {
templateArguments = createTemplateArgumentArray((ICPPASTTemplateId) name); templateArguments = createTemplateArgumentArray((ICPPASTTemplateId) name);
if (hasDependentArgument(templateArguments)) if (hasDependentArgument(templateArguments)) {
return new IFunction[] {CPPUnknownFunction.createForSample(templates.keyAt(0), name)}; functions[i]= CPPUnknownFunction.createForSample(template, name);
return;
}
} }
} catch (DOMException e) { } catch (DOMException e) {
return new IFunction[0]; return;
}
} }
IFunction[] instances= null;
final int size = templates.size();
for (int idx = 0; idx < size; idx++) {
ICPPFunctionTemplate template = (ICPPFunctionTemplate) templates.keyAt(idx);
CPPTemplateParameterMap map= new CPPTemplateParameterMap(fnArgs.length); CPPTemplateParameterMap map= new CPPTemplateParameterMap(fnArgs.length);
try { try {
ICPPTemplateArgument[] useArgs = templateArguments; ICPPTemplateArgument[] args= deduceTemplateFunctionArguments(template, templateArguments, fnArgs, map);
if (template instanceof ICPPConstructor)
useArgs= ICPPTemplateArgument.EMPTY_ARGUMENTS;
ICPPTemplateArgument[] args= deduceTemplateFunctionArguments(template, useArgs, fnArgs, map);
if (args != null) { if (args != null) {
IBinding temp= instantiateFunctionTemplate(template, args); IBinding instance= instantiateFunctionTemplate(template, args);
if (temp instanceof IFunction) { if (instance instanceof IFunction) {
instances = (IFunction[]) ArrayUtil.append(IFunction.class, instances, temp); functions[i]= (IFunction) instance;
} }
} }
} catch (DOMException e) { } catch (DOMException e) {
// try next candidate // try next candidate
} }
} }
}
return (IFunction[]) ArrayUtil.trim(IFunction.class, instances);
} }
/** /**

View file

@ -52,17 +52,17 @@ public class Conversions {
/** /**
* Computes the cost of an implicit conversion sequence * Computes the cost of an implicit conversion sequence
* [over.best.ics] 13.3.3.1 * [over.best.ics] 13.3.3.1
*
* @param allowUDC whether a user-defined conversion is allowed during the sequence
* @param sourceExp the expression behind the source type * @param sourceExp the expression behind the source type
* @param source the source (argument) type * @param source the source (argument) type
* @param target the target (parameter) type * @param target the target (parameter) type
* @param allowUDC whether a user-defined conversion is allowed during the sequence
* @param isImpliedObject * @param isImpliedObject
*
* @return the cost of converting from source to target * @return the cost of converting from source to target
* @throws DOMException * @throws DOMException
*/ */
public static Cost checkImplicitConversionSequence(boolean allowUDC, IASTExpression sourceExp, public static Cost checkImplicitConversionSequence(IASTExpression sourceExp, IType source,
IType source, IType target, boolean isImpliedObject) throws DOMException { IType target, boolean allowUDC, boolean isImpliedObject) throws DOMException {
allowUDC &= !isImpliedObject; allowUDC &= !isImpliedObject;
target= getNestedType(target, TYPEDEFS); target= getNestedType(target, TYPEDEFS);
source= getNestedType(source, TYPEDEFS); source= getNestedType(source, TYPEDEFS);
@ -166,26 +166,20 @@ public class Conversions {
// We must do a non-reference initialization // We must do a non-reference initialization
if (!illformed) { if (!illformed) {
Cost cost= checkStandardConversionSequence(source, cv1T1, isImpliedObject); return nonReferenceConversion(source, cv1T1, allowUDC, isImpliedObject);
// 12.3-4 At most one user-defined conversion is implicitly applied to
// a single value. (also prevents infinite loop)
if (allowUDC && (cost.rank == Cost.NO_MATCH_RANK ||
cost.rank == Cost.FUZZY_TEMPLATE_PARAMETERS)) {
Cost temp = checkUserDefinedConversionSequence(source, cv1T1);
if (temp != null) {
cost = temp;
}
}
return cost;
} }
} }
return new Cost(source, cv1T1); return new Cost(source, cv1T1);
} }
// Non-reference binding // Non-reference binding
return nonReferenceConversion(source, target, allowUDC, isImpliedObject);
}
private static Cost nonReferenceConversion(IType source, IType target, boolean allowUDC,
boolean isImpliedObject) throws DOMException {
Cost cost= checkStandardConversionSequence(source, target, isImpliedObject); Cost cost= checkStandardConversionSequence(source, target, isImpliedObject);
if (allowUDC && (cost.rank == Cost.NO_MATCH_RANK || if (allowUDC && cost.rank == Cost.NO_MATCH_RANK) {
cost.rank == Cost.FUZZY_TEMPLATE_PARAMETERS)) {
Cost temp = checkUserDefinedConversionSequence(source, target); Cost temp = checkUserDefinedConversionSequence(source, target);
if (temp != null) { if (temp != null) {
cost = temp; cost = temp;
@ -349,15 +343,20 @@ public class Conversions {
//constructors //constructors
if (t instanceof ICPPClassType) { if (t instanceof ICPPClassType) {
ICPPConstructor [] constructors= ((ICPPClassType) t).getConstructors(); ICPPConstructor[] ctors= ((ICPPClassType) t).getConstructors();
if (constructors.length > 0 && !(constructors[0] instanceof IProblemBinding)) { // select converting constructors
int j= 0;
ICPPConstructor[] convertingCtors= new ICPPConstructor[ctors.length];
for (int i = 0; i < ctors.length; i++) {
ICPPConstructor ctor= ctors[i];
if (!(ctor instanceof IProblemBinding) && !ctor.isExplicit())
convertingCtors[j++]= ctor;
}
if (j > 0) {
LookupData data= new LookupData(); LookupData data= new LookupData();
data.forUserDefinedConversion= true;
data.functionParameters= new IType [] { source }; data.functionParameters= new IType [] { source };
IBinding binding = CPPSemantics.resolveFunction(data, constructors); IBinding binding = CPPSemantics.resolveFunction(data, convertingCtors, false);
if (binding instanceof ICPPConstructor) { if (binding instanceof ICPPConstructor && !(binding instanceof IProblemBinding)) {
ICPPConstructor constructor= (ICPPConstructor) binding;
if (!constructor.isExplicit()) {
constructorCost = checkStandardConversionSequence(t, target, false); constructorCost = checkStandardConversionSequence(t, target, false);
if (constructorCost.rank == Cost.NO_MATCH_RANK) { if (constructorCost.rank == Cost.NO_MATCH_RANK) {
constructorCost= null; constructorCost= null;
@ -365,7 +364,6 @@ public class Conversions {
} }
} }
} }
}
//conversion operators //conversion operators
boolean ambiguousConversionOperator= false; boolean ambiguousConversionOperator= false;

View file

@ -37,7 +37,6 @@ class Cost {
public static final int DERIVED_TO_BASE_CONVERSION = 3; public static final int DERIVED_TO_BASE_CONVERSION = 3;
public static final int USERDEFINED_CONVERSION_RANK = 4; public static final int USERDEFINED_CONVERSION_RANK = 4;
public static final int ELLIPSIS_CONVERSION = 5; public static final int ELLIPSIS_CONVERSION = 5;
public static final int FUZZY_TEMPLATE_PARAMETERS = 6;
public IType source; public IType source;
public IType target; public IType target;

View file

@ -93,7 +93,6 @@ public class LookupData {
public boolean ignoreUsingDirectives = false; public boolean ignoreUsingDirectives = false;
public boolean usingDirectivesOnly = false; public boolean usingDirectivesOnly = false;
public boolean forceQualified = false; public boolean forceQualified = false;
public boolean forUserDefinedConversion = false;
public boolean forAssociatedScopes = false; public boolean forAssociatedScopes = false;
public boolean contentAssist = false; public boolean contentAssist = false;
public boolean prefixLookup = false; public boolean prefixLookup = false;

View file

@ -29,7 +29,6 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPMethod;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPPointerToMemberType; 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.ICPPReferenceType;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateArgument; import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateArgument;
import org.eclipse.cdt.core.model.ITypeDef;
import org.eclipse.cdt.core.parser.Keywords; import org.eclipse.cdt.core.parser.Keywords;
import org.eclipse.cdt.core.parser.util.ArrayUtil; import org.eclipse.cdt.core.parser.util.ArrayUtil;
import org.eclipse.cdt.core.parser.util.CharArraySet; import org.eclipse.cdt.core.parser.util.CharArraySet;
@ -284,7 +283,7 @@ public class SemanticUtil {
return new CPPFunctionType(ret, params, ((ICPPFunctionType) type).getThisType()); return new CPPFunctionType(ret, params, ((ICPPFunctionType) type).getThisType());
} }
if (type instanceof ITypeDef) { if (type instanceof ITypedef) {
IType t= ((ITypedef) type).getType(); IType t= ((ITypedef) type).getType();
if (t != null) if (t != null)
return getSimplifiedType(t); return getSimplifiedType(t);