1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-07-24 09:25:31 +02:00

Invalid attempts of using user-defined conversions, bug 269729.

This commit is contained in:
Markus Schorn 2009-03-23 20:27:40 +00:00
parent f95a890c94
commit 32878a0b93
18 changed files with 189 additions and 144 deletions

View file

@ -32,7 +32,7 @@ public interface ICPPMethod extends ICPPFunction, ICPPMember {
*
* returns true if its name starts with '~'
*/
public boolean isDestructor() throws DOMException;
public boolean isDestructor();
/**
* Returns whether this is an implicit method (constructor, assignment operator, etc.)

View file

@ -28,7 +28,7 @@ public class CPPUnknownConstructor extends CPPUnknownFunction implements ICPPCon
return false;
}
public boolean isDestructor() throws DOMException {
public boolean isDestructor() {
return false;
}

View file

@ -198,7 +198,7 @@ public class CPPSemantics {
public static int traceIndent= 0;
// special return value for costForFunctionCall
private static final Cost[] CONTAINS_DEPENDENT_TYPES = {};
private static final FunctionCost CONTAINS_DEPENDENT_TYPES = new FunctionCost(null, 0);
static protected IBinding resolveBinding(IASTName name) {
@ -1845,9 +1845,9 @@ public class CPPSemantics {
} else if (type != temp) {
int c = compareByRelevance(data, type, temp);
if (c < 0) {
type= temp;
type= temp;
} else if (c == 0) {
if (((IType) type).isSameType((IType) temp)) {
if (((IType)type).isSameType((IType) temp)) {
if (type instanceof ITypedef && !(temp instanceof ITypedef)) {
// Between same types prefer non-typedef.
type= temp;
@ -1855,7 +1855,7 @@ public class CPPSemantics {
} else {
return new ProblemBinding(data.astName, IProblemBinding.SEMANTIC_AMBIGUOUS_LOOKUP);
}
}
}
}
} else {
if (obj == null) {
@ -1865,7 +1865,7 @@ public class CPPSemantics {
} else {
int c = compareByRelevance(data, obj, temp);
if (c < 0) {
obj= temp;
obj= temp;
} else if (c == 0) {
return new ProblemBinding(data.astName, IProblemBinding.SEMANTIC_AMBIGUOUS_LOOKUP);
}
@ -1922,7 +1922,7 @@ public class CPPSemantics {
* the two bindings have the same relevance; -1 if <code>b1</code> is less relevant than
* <code>b2</code>.
*/
private static int compareByRelevance(LookupData data, IBinding b1, IBinding b2) {
static int compareByRelevance(LookupData data, IBinding b1, IBinding b2) {
boolean b1FromIndex= isFromIndex(b1);
boolean b2FromIndex= isFromIndex(b2);
if (b1FromIndex != b2FromIndex) {
@ -1949,7 +1949,7 @@ public class CPPSemantics {
}
return false;
}
/**
* Checks if a binding belongs to an AST or is reachable from it through includes.
* @param ast
@ -2114,16 +2114,14 @@ public class CPPSemantics {
}
boolean ambiguous = false; // ambiguity, 2 functions are equally good
IFunction bestFn = null; // the best function
Cost[] bestFnCost = null; // the cost of the best function
boolean bestHasAmbiguousParam = false; // bestFn has an ambiguous parameter conversion (not ok, ambiguous)
FunctionCost bestFnCost = null; // the cost of the best function
// Loop over all functions
for (IFunction fn : fns) {
if (fn == null || bestFn == fn)
if (fn == null)
continue;
final Cost[] fnCost= costForFunctionCall(fn, argTypes, args, allowUDC, data);
final FunctionCost fnCost= costForFunctionCall(fn, argTypes, args, allowUDC, data);
if (fnCost == null)
continue;
@ -2133,101 +2131,26 @@ public class CPPSemantics {
return CPPUnknownFunction.createForSample(firstViable, data.astName);
}
if (bestFnCost == null) {
int cmp= fnCost.compareTo(data, bestFnCost);
if (cmp < 0) {
bestFnCost= fnCost;
bestFn= fn;
continue;
}
boolean hasWorse = false;
boolean hasBetter = false;
boolean hasAmbiguousParam= false;
// In order for this function to be better than the previous best, it must
// have at least one parameter match that is better that the corresponding
// match for the other function, and none that are worse.
int len = Math.min(fnCost.length, bestFnCost.length);
for (int j = 1; j <= len; j++) {
Cost currCost = fnCost[fnCost.length - j];
if (currCost.getRank() == Rank.NO_MATCH) {
hasWorse = true;
hasBetter = false;
break;
}
// An ambiguity in the user defined conversion sequence is only a problem
// if this function turns out to be the best.
if (currCost.isAmbiguousUserdefinedConversion())
hasAmbiguousParam = true;
if (bestFnCost != null) {
int comparison = currCost.compare(bestFnCost[bestFnCost.length - j]);
hasWorse |= (comparison > 0);
hasBetter |= (comparison < 0);
} else {
hasBetter = true;
}
}
if (!hasWorse && !hasBetter) {
// If they are both template functions, we can order them that way
ICPPFunctionTemplate bestAsTemplate= asTemplate(bestFn);
ICPPFunctionTemplate currAsTemplate= asTemplate(fn);
final boolean bestIsTemplate = bestAsTemplate != null;
final boolean currIsTemplate = currAsTemplate != null;
if (bestIsTemplate && currIsTemplate) {
int order = CPPTemplates.orderTemplateFunctions(bestAsTemplate, currAsTemplate);
if (order < 0) {
hasBetter= true;
} else if (order > 0) {
hasWorse= true;
}
} else if (bestIsTemplate != currIsTemplate) {
// We prefer normal functions over template functions, unless we specified template arguments
if (data.preferTemplateFunctions() == bestIsTemplate)
hasWorse = true;
else
hasBetter = true;
}
}
// Ff we are ambiguous at this point, prefer a non-index binding or reachable index one.
if (hasBetter == hasWorse) {
int c = compareByRelevance(data, bestFn, fn);
if (c != 0) {
hasBetter = (c < 0);
hasWorse = !hasBetter;
}
// final boolean bestIsFromIndex= isFromIndex(bestFn);
// final boolean currIsFromIndex= isFromIndex(fn);
// if (bestIsFromIndex != currIsFromIndex) {
// hasBetter= bestIsFromIndex;
// hasWorse= currIsFromIndex;
// }
}
// If function has a parameter match that is better than the current best,
// and another that is worse (or everything was just as good, neither better nor worse),
// then this is an ambiguity (unless we find something better than both later).
if (hasBetter == hasWorse) {
ambiguous= true;
// here we would need to store the costs to compare to a function that is better later on.
} else if (hasBetter && !hasWorse) {
bestFn= fn;
bestFnCost= fnCost;
bestHasAmbiguousParam= hasAmbiguousParam;
ambiguous= false;
// here we would have to compare to the functions that were previously ambiguous.
}
} else if (cmp == 0) {
ambiguous= true;
}
}
if (ambiguous || bestHasAmbiguousParam) {
if (bestFnCost == null)
return null;
if (ambiguous || bestFnCost.hasAmbiguousUserDefinedConversion()) {
return new ProblemBinding(data.astName, IProblemBinding.SEMANTIC_AMBIGUOUS_LOOKUP);
}
return bestFn;
return bestFnCost.getFunction();
}
private static Cost[] costForFunctionCall(IFunction fn, IType[] argTypes, IASTExpression[] args, boolean allowUDC, LookupData data) throws DOMException {
private static FunctionCost costForFunctionCall(IFunction fn, IType[] argTypes, IASTExpression[] args, boolean allowUDC, LookupData data) throws DOMException {
final ICPPFunctionType ftype= (ICPPFunctionType) fn.getType();
if (ftype == null)
return null;
@ -2245,11 +2168,11 @@ public class CPPSemantics {
int k= 0;
Cost cost;
final int sourceLen= argTypes.length;
final Cost[] result;
final FunctionCost result;
if (implicitType == null) {
result= new Cost[sourceLen];
result= new FunctionCost(fn, sourceLen);
} else {
result= new Cost[sourceLen+1];
result= new FunctionCost(fn, sourceLen+1);
final IType thisType = data.getImpliedObjectArgument();
@ -2268,7 +2191,7 @@ public class CPPSemantics {
if (cost.getRank() == Rank.NO_MATCH)
return null;
result[k++] = cost;
result.setCost(k++, cost);
}
for (int j = 0; j < sourceLen; j++) {
@ -2285,7 +2208,7 @@ public class CPPSemantics {
paramType= VOID_TYPE;
} else {
cost = new Cost(argType, null, Rank.ELLIPSIS_CONVERSION);
result[k++]= cost;
result.setCost(k++, cost);
continue;
}
@ -2299,7 +2222,7 @@ public class CPPSemantics {
if (cost.getRank() == Rank.NO_MATCH)
return null;
result[k++] = cost;
result.setCost(k++, cost);
}
return result;
}
@ -2346,16 +2269,6 @@ public class CPPSemantics {
return new ProblemBinding(astName, IProblemBinding.SEMANTIC_NAME_NOT_FOUND);
}
private static ICPPFunctionTemplate asTemplate(IFunction function) {
if (function instanceof ICPPSpecialization) {
IBinding original= ((ICPPSpecialization) function).getSpecializedBinding();
if (original instanceof ICPPFunctionTemplate) {
return (ICPPFunctionTemplate) original;
}
}
return null;
}
/**
* 13.4-1 A use of an overloaded function without arguments is resolved in certain contexts to a function
* @param data
@ -2417,7 +2330,7 @@ public class CPPSemantics {
result= fn;
} else if (c == 0) {
return new ProblemBinding(data.astName, IProblemBinding.SEMANTIC_AMBIGUOUS_LOOKUP);
}
}
// boolean fromIndex= isFromIndex(fn);
// if (isFromIndex(result) == fromIndex)
// return new ProblemBinding(data.astName, IProblemBinding.SEMANTIC_AMBIGUOUS_LOOKUP);

View file

@ -1339,6 +1339,16 @@ public class CPPTemplates {
}
static protected void instantiateFunctionTemplates(IFunction[] functions, IType[] fnArgs, IASTName name) {
boolean requireTemplate= false;
if (name != null) {
if (name.getPropertyInParent() == ICPPASTTemplateId.TEMPLATE_NAME) {
name= (IASTName) name.getParent();
requireTemplate= true;
} else if (name instanceof ICPPASTTemplateId) {
requireTemplate= true;
}
}
ICPPTemplateArgument[] templateArguments= null;
for (int i = 0; i < functions.length; i++) {
IFunction func = functions[i];
@ -1377,7 +1387,11 @@ public class CPPTemplates {
} catch (DOMException e) {
// try next candidate
}
}
} else if (requireTemplate
&& !(func instanceof ICPPConstructor) && !(func instanceof ICPPUnknownBinding)
&& !(func instanceof ICPPMethod && ((ICPPMethod) func).isDestructor())) {
functions[i]= null;
}
}
}

View file

@ -322,8 +322,8 @@ public class Conversions {
Cost constructorCost= null;
Cost operatorCost= null;
IType s= getUltimateType(source, true);
IType t= getUltimateType(target, true);
IType s= getNestedType(source, TDEF | CVQ | REF);
IType t= getNestedType(target, TDEF | CVQ | REF);
//constructors
if (t instanceof ICPPClassType) {

View file

@ -0,0 +1,125 @@
/*******************************************************************************
* Copyright (c) 2009 Wind River Systems, Inc. and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Markus Schorn - initial API and implementation
*******************************************************************************/
package org.eclipse.cdt.internal.core.dom.parser.cpp.semantics;
import org.eclipse.cdt.core.dom.ast.DOMException;
import org.eclipse.cdt.core.dom.ast.IBinding;
import org.eclipse.cdt.core.dom.ast.IFunction;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPFunctionTemplate;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPSpecialization;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.Cost.Rank;
/**
* Cost for the entire function call
*/
class FunctionCost {
private final IFunction fFunction;
private final Cost[] fCosts;
public FunctionCost(IFunction fn, int paramCount) {
fFunction= fn;
fCosts= new Cost[paramCount];
}
public int getLength() {
return fCosts.length;
}
public Cost getCost(int idx) {
return fCosts[idx];
}
public void setCost(int idx, Cost cost) {
fCosts[idx]= cost;
}
public IFunction getFunction() {
return fFunction;
}
public boolean hasAmbiguousUserDefinedConversion() {
for (Cost cost : fCosts) {
if (cost.isAmbiguousUserdefinedConversion())
return true;
}
return false;
}
/**
* Compares this function call cost to another one.
*/
public int compareTo(LookupData data, FunctionCost other) throws DOMException {
if (other == null)
return -1;
boolean haveWorse = false;
boolean haveBetter = false;
// In order for this function to be better than the previous best, it must
// have at least one parameter match that is better that the corresponding
// match for the other function, and none that are worse.
int idx= getLength()-1;
int idxOther= other.getLength()-1;
for (; idx>=0 && idxOther>=0; idx--,idxOther--) {
Cost cost= getCost(idx);
if (cost.getRank() == Rank.NO_MATCH) {
haveWorse = true;
haveBetter = false;
break;
}
int cmp = cost.compare(other.getCost(idxOther));
haveWorse |= (cmp > 0);
haveBetter |= (cmp < 0);
}
if (!haveWorse && !haveBetter) {
// If they are both template functions, we can order them that way
ICPPFunctionTemplate asTemplate= asTemplate(getFunction());
ICPPFunctionTemplate otherAsTemplate= asTemplate(other.getFunction());
final boolean isTemplate = asTemplate != null;
final boolean otherIsTemplate = otherAsTemplate != null;
// Prefer normal functions over template functions
if (isTemplate && !otherIsTemplate) {
haveWorse = true;
} else if (!isTemplate && otherIsTemplate) {
haveBetter = true;
} else if (isTemplate && otherIsTemplate) {
int order = CPPTemplates.orderTemplateFunctions(otherAsTemplate, asTemplate);
if (order < 0) {
haveBetter= true;
} else if (order > 0) {
haveWorse= true;
}
}
}
// if we are ambiguous at this point prefer non-index bindings
if (haveBetter == haveWorse) {
return -CPPSemantics.compareByRelevance(data, getFunction(), other.getFunction());
}
if (haveBetter)
return -1;
return 1;
}
private static ICPPFunctionTemplate asTemplate(IFunction function) {
if (function instanceof ICPPSpecialization) {
IBinding original= ((ICPPSpecialization) function).getSpecializedBinding();
if (original instanceof ICPPFunctionTemplate) {
return (ICPPFunctionTemplate) original;
}
}
return null;
}
}

View file

@ -550,12 +550,6 @@ public class LookupData {
return false;
}
public boolean preferTemplateFunctions() {
if (astName == null)
return false;
return (astName instanceof ICPPASTTemplateId || astName.getPropertyInParent() == ICPPASTTemplateId.TEMPLATE_NAME);
}
public void setFunctionArguments(IASTExpression args) {
IASTExpression[] exprs;
if (args instanceof IASTExpressionList) {

View file

@ -166,9 +166,8 @@ public class SemanticUtil {
* @return the deepest type in a type container sequence
*/
public static IType getUltimateType(IType type, boolean stopAtPointerToMember) {
if (stopAtPointerToMember)
return getNestedType(type, TDEF | CVQ | PTR | ARRAY | REF);
return getNestedType(type, TDEF | CVQ | PTR | ARRAY | MPTR | REF);
final int options = TDEF | CVQ | PTR | ARRAY | REF;
return getNestedType(type, stopAtPointerToMember ? options : (options | MPTR));
}
/**

View file

@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2007, 2008 Symbian Software Systems and others.
* Copyright (c) 2007, 2009 Symbian Software Systems and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@ -23,7 +23,7 @@ class CompositeCPPMethod extends CompositeCPPFunction implements ICPPMethod {
super(cf, rbinding);
}
public boolean isDestructor() throws DOMException {
public boolean isDestructor() {
return ((ICPPMethod)rbinding).isDestructor();
}

View file

@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2007, 2008 Symbian Software Systems and others.
* Copyright (c) 2007, 2009 Symbian Software Systems and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@ -22,7 +22,7 @@ public class CompositeCPPMethodInstance extends CompositeCPPFunctionInstance imp
super(cf, rbinding);
}
public boolean isDestructor() throws DOMException {
public boolean isDestructor() {
return ((ICPPMethod)rbinding).isDestructor();
}

View file

@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2007, 2008 Symbian Software Systems and others.
* Copyright (c) 2007, 2009 Symbian Software Systems and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@ -23,7 +23,7 @@ implements ICPPMethod {
super(cf, method);
}
public boolean isDestructor() throws DOMException {
public boolean isDestructor() {
return ((ICPPMethod)rbinding).isDestructor();
}

View file

@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2007, 2008 Symbian Software Systems and others.
* Copyright (c) 2007, 2009 Symbian Software Systems and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@ -22,7 +22,7 @@ public class CompositeCPPMethodTemplate extends CompositeCPPFunctionTemplate imp
super(cf, rbinding);
}
public boolean isDestructor() throws DOMException {
public boolean isDestructor() {
return ((ICPPMethod)rbinding).isDestructor();
}

View file

@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2007, 2008 Symbian Software Systems and others.
* Copyright (c) 2007, 2009 Symbian Software Systems and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@ -26,7 +26,7 @@ public class CompositeCPPMethodTemplateSpecialization
super(cf, ft);
}
public boolean isDestructor() throws DOMException {
public boolean isDestructor() {
return ((ICPPMethod)rbinding).isDestructor();
}

View file

@ -118,7 +118,7 @@ class PDOMCPPMethod extends PDOMCPPFunction implements ICPPMethod {
return getBit(getAnnotation1(), PDOMCPPAnnotation.PURE_VIRTUAL_OFFSET);
}
public boolean isDestructor() throws DOMException {
public boolean isDestructor() {
return getBit(getAnnotation1(), PDOMCPPAnnotation.DESTRUCTOR_OFFSET);
}

View file

@ -51,7 +51,7 @@ class PDOMCPPMethodInstance extends PDOMCPPFunctionInstance implements ICPPMetho
return IIndexCPPBindingConstants.CPP_METHOD_INSTANCE;
}
public boolean isDestructor() throws DOMException {
public boolean isDestructor() {
return ((ICPPMethod)getTemplateDefinition()).isDestructor();
}

View file

@ -79,7 +79,7 @@ class PDOMCPPMethodSpecialization extends PDOMCPPFunctionSpecialization
return IIndexCPPBindingConstants.CPP_METHOD_SPECIALIZATION;
}
public boolean isDestructor() throws DOMException {
public boolean isDestructor() {
return getBit(getByte(record + ANNOTATION1), PDOMCPPAnnotation.DESTRUCTOR_OFFSET);
}

View file

@ -80,7 +80,7 @@ class PDOMCPPMethodTemplate extends PDOMCPPFunctionTemplate implements ICPPMetho
return IIndexCPPBindingConstants.CPP_METHOD_TEMPLATE;
}
public boolean isDestructor() throws DOMException {
public boolean isDestructor() {
return getBit(getAnnotation1(), PDOMCPPAnnotation.DESTRUCTOR_OFFSET);
}

View file

@ -43,7 +43,7 @@ class PDOMCPPMethodTemplateSpecialization extends
return IIndexCPPBindingConstants.CPP_METHOD_TEMPLATE_SPECIALIZATION;
}
public boolean isDestructor() throws DOMException {
public boolean isDestructor() {
IBinding spec = getSpecializedBinding();
if (spec instanceof ICPPMethod) {
((ICPPMethod)spec).isDestructor();