1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-08-10 01:35: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();
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) {
return e.getProblem();
}
return new CPPPointerToMemberType(type, (ICPPClassType) nestedType,
thisType.isConst(), thisType.isVolatile());
return new CPPPointerToMemberType(type, nestedType, thisType.isConst(), thisType
.isVolatile());
}
}
return new CPPPointerType(type);

View file

@ -1651,13 +1651,10 @@ public class CPPSemantics {
final boolean indexBased= data.tu != null && data.tu.getIndex() != null;
@SuppressWarnings("unchecked")
ObjectSet<IFunction> fns= ObjectSet.EMPTY_SET;
@SuppressWarnings("unchecked")
ObjectSet<IFunction> templateFns= ObjectSet.EMPTY_SET;
IBinding type = null;
IBinding obj = null;
IBinding temp = null;
boolean fnsFromAST= false;
boolean fnTmplsFromAST= false;
Object[] items = (Object[]) data.foundItems;
for (int i = 0; i < items.length && items[i] != null; i++) {
@ -1713,36 +1710,19 @@ public class CPPSemantics {
}
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)
fns = new ObjectSet<IFunction>(2);
if (isFromIndex(function)) {
// accept bindings from index only, in case we have none in the AST
if (!fnsFromAST) {
fns.put(function);
}
} else {
if (!fnsFromAST) {
fns.clear();
fnsFromAST= true;
}
if (fns == ObjectSet.EMPTY_SET)
fns = new ObjectSet<IFunction>(2);
if (isFromIndex(function)) {
// accept bindings from index only, in case we have none in the AST
if (!fnsFromAST) {
fns.put(function);
}
} else {
if (!fnsFromAST) {
fns.clear();
fnsFromAST= true;
}
fns.put(function);
}
} else if (temp instanceof IType) {
// specializations are selected during instantiation
@ -1804,46 +1784,31 @@ public class CPPSemantics {
// if (fns == null) return 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, templateFns.keyArray());
}
bindings = (IBinding[]) ArrayUtil.trim(IBinding.class, bindings);
ICPPUsingDeclaration composite = new CPPUsingDeclaration(data.astName, bindings);
return composite;
}
int numTemplateFns = templateFns.size();
if (numTemplateFns > 0) {
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))
if (data.typesOnly) {
if (type != null)
return type;
if (obj instanceof ICPPNamespace)
return obj;
return null;
}
int numFns = fns.size();
if (numFns > 0) {
if (obj != null)
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) {
return null;
if (obj != null) {
return obj;
}
return obj;
return type;
}
private static boolean isFromIndex(IBinding binding) {
@ -1878,12 +1843,14 @@ public class CPPSemantics {
// Trim the list down to the set of viable functions
IFunction function = null;
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];
if (function == null)
continue;
if (function instanceof IProblemBinding) {
functions[i]= null;
continue;
}
}
if (function instanceof ICPPUnknownBinding) {
if (def) {
functions[i]= null;
@ -1978,7 +1945,7 @@ public class CPPSemantics {
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);
if (fns == null || fns.length == 0)
return null;
@ -1987,14 +1954,19 @@ public class CPPSemantics {
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
if (data.functionParameters == null) {
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
reduceToViable(data, fns);
@ -2060,7 +2032,6 @@ public class CPPSemantics {
currFnCost= new Cost[sourceLen];
}
comparison = 0;
boolean varArgs = false;
boolean isImpliedObject= false;
for (int j = 0; j < sourceLen; j++) {
@ -2097,8 +2068,8 @@ public class CPPSemantics {
cost = new Cost(source, target);
cost.rank = Cost.IDENTITY_RANK; // exact match, no cost
} else {
cost= Conversions.checkImplicitConversionSequence(!data.forUserDefinedConversion,
sourceExp, source, target, isImpliedObject);
cost= Conversions.checkImplicitConversionSequence(sourceExp,
source, target, allowUDC, isImpliedObject);
}
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.CharArrayUtils;
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.ASTQueries;
import org.eclipse.cdt.internal.core.dom.parser.IASTInternalScope;
@ -1332,50 +1331,50 @@ public class CPPTemplates {
return result;
}
static protected IFunction[] selectTemplateFunctions(ObjectSet<IFunction> templates,
static protected void instantiateFunctionTemplates(IFunction[] functions,
Object[] functionArguments, IASTName name) {
if (templates == null || templates.size() == 0)
return null;
ICPPTemplateArgument[] templateArguments = ICPPTemplateArgument.EMPTY_ARGUMENTS;
final IType[] fnArgs= createTypeArray(functionArguments);
try {
if (containsDependentType(fnArgs))
return new IFunction[] {CPPUnknownFunction.createForSample(templates.keyAt(0), name)};
if (name instanceof ICPPASTTemplateId) {
templateArguments = createTemplateArgumentArray((ICPPASTTemplateId) name);
if (hasDependentArgument(templateArguments))
return new IFunction[] {CPPUnknownFunction.createForSample(templates.keyAt(0), name)};
}
} catch (DOMException e) {
return new IFunction[0];
}
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);
try {
ICPPTemplateArgument[] useArgs = templateArguments;
if (template instanceof ICPPConstructor)
useArgs= ICPPTemplateArgument.EMPTY_ARGUMENTS;
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;
ICPPTemplateArgument[] args= deduceTemplateFunctionArguments(template, useArgs, fnArgs, map);
if (args != null) {
IBinding temp= instantiateFunctionTemplate(template, args);
if (temp instanceof IFunction) {
instances = (IFunction[]) ArrayUtil.append(IFunction.class, instances, temp);
// extract template arguments and parameter types.
if (templateArguments == null || fnArgs == null) {
templateArguments = ICPPTemplateArgument.EMPTY_ARGUMENTS;
fnArgs= createTypeArray(functionArguments);
try {
if (containsDependentType(fnArgs)) {
functions[i]= CPPUnknownFunction.createForSample(template, name);
return;
}
if (name instanceof ICPPASTTemplateId && !(template instanceof ICPPConstructor)) {
templateArguments = createTemplateArgumentArray((ICPPASTTemplateId) name);
if (hasDependentArgument(templateArguments)) {
functions[i]= CPPUnknownFunction.createForSample(template, name);
return;
}
}
} catch (DOMException e) {
return;
}
}
} catch (DOMException e) {
// try next candidate
}
CPPTemplateParameterMap map= new CPPTemplateParameterMap(fnArgs.length);
try {
ICPPTemplateArgument[] args= deduceTemplateFunctionArguments(template, templateArguments, fnArgs, map);
if (args != null) {
IBinding instance= instantiateFunctionTemplate(template, args);
if (instance instanceof IFunction) {
functions[i]= (IFunction) instance;
}
}
} catch (DOMException e) {
// 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
* [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 source the source (argument) type
* @param target the target (parameter) type
* @param allowUDC whether a user-defined conversion is allowed during the sequence
* @param isImpliedObject
*
* @return the cost of converting from source to target
* @throws DOMException
*/
public static Cost checkImplicitConversionSequence(boolean allowUDC, IASTExpression sourceExp,
IType source, IType target, boolean isImpliedObject) throws DOMException {
public static Cost checkImplicitConversionSequence(IASTExpression sourceExp, IType source,
IType target, boolean allowUDC, boolean isImpliedObject) throws DOMException {
allowUDC &= !isImpliedObject;
target= getNestedType(target, TYPEDEFS);
source= getNestedType(source, TYPEDEFS);
@ -166,26 +166,20 @@ public class Conversions {
// We must do a non-reference initialization
if (!illformed) {
Cost cost= checkStandardConversionSequence(source, cv1T1, 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 nonReferenceConversion(source, cv1T1, allowUDC, isImpliedObject);
}
}
return new Cost(source, cv1T1);
}
// 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);
if (allowUDC && (cost.rank == Cost.NO_MATCH_RANK ||
cost.rank == Cost.FUZZY_TEMPLATE_PARAMETERS)) {
if (allowUDC && cost.rank == Cost.NO_MATCH_RANK) {
Cost temp = checkUserDefinedConversionSequence(source, target);
if (temp != null) {
cost = temp;
@ -349,19 +343,23 @@ public class Conversions {
//constructors
if (t instanceof ICPPClassType) {
ICPPConstructor [] constructors= ((ICPPClassType) t).getConstructors();
if (constructors.length > 0 && !(constructors[0] instanceof IProblemBinding)) {
ICPPConstructor[] ctors= ((ICPPClassType) t).getConstructors();
// 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();
data.forUserDefinedConversion= true;
data.functionParameters= new IType [] { source };
IBinding binding = CPPSemantics.resolveFunction(data, constructors);
if (binding instanceof ICPPConstructor) {
ICPPConstructor constructor= (ICPPConstructor) binding;
if (!constructor.isExplicit()) {
constructorCost = checkStandardConversionSequence(t, target, false);
if (constructorCost.rank == Cost.NO_MATCH_RANK) {
constructorCost= null;
}
IBinding binding = CPPSemantics.resolveFunction(data, convertingCtors, false);
if (binding instanceof ICPPConstructor && !(binding instanceof IProblemBinding)) {
constructorCost = checkStandardConversionSequence(t, target, false);
if (constructorCost.rank == Cost.NO_MATCH_RANK) {
constructorCost= null;
}
}
}

View file

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

View file

@ -93,7 +93,6 @@ public class LookupData {
public boolean ignoreUsingDirectives = false;
public boolean usingDirectivesOnly = false;
public boolean forceQualified = false;
public boolean forUserDefinedConversion = false;
public boolean forAssociatedScopes = false;
public boolean contentAssist = 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.ICPPReferenceType;
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.util.ArrayUtil;
import org.eclipse.cdt.core.parser.util.CharArraySet;
@ -284,7 +283,7 @@ public class SemanticUtil {
return new CPPFunctionType(ret, params, ((ICPPFunctionType) type).getThisType());
}
if (type instanceof ITypeDef) {
if (type instanceof ITypedef) {
IType t= ((ITypedef) type).getType();
if (t != null)
return getSimplifiedType(t);