mirror of
https://github.com/eclipse-cdt/cdt
synced 2025-07-19 15:05:36 +02:00
Bug 509396 - Unresolved symbol with address of overload set containing
function templates This change fixes the examples contained in https://bugs.eclipse.org/bugs/show_bug.cgi?id=509396#c0 and https://bugs.eclipse.org/bugs/show_bug.cgi?id=509396#c4 Change-Id: Id5c81469b6700ddc775ab714b0b68d5ea9a809ae
This commit is contained in:
parent
8bfd2cdc22
commit
8da53f1e5e
8 changed files with 135 additions and 23 deletions
|
@ -5969,6 +5969,43 @@ public class AST2TemplateTests extends AST2TestBase {
|
|||
parseAndCheckBindings();
|
||||
}
|
||||
|
||||
// struct A {
|
||||
// template <typename U>
|
||||
// void m(U);
|
||||
// int m(int);
|
||||
// };
|
||||
//
|
||||
// void foo(void(A::*)(int));
|
||||
// void foo(int);
|
||||
//
|
||||
// template <typename T>
|
||||
// decltype(foo(&T::m)) waldo(T);
|
||||
//
|
||||
// int main() {
|
||||
// waldo(A());
|
||||
// }
|
||||
public void testAddressOfMethodTargeted_509396() throws Exception {
|
||||
parseAndCheckBindings();
|
||||
}
|
||||
|
||||
// struct A {
|
||||
// template <typename U>
|
||||
// void m(U t);
|
||||
// };
|
||||
//
|
||||
// template <typename T>
|
||||
// void waldo(T t);
|
||||
//
|
||||
// template <typename T>
|
||||
// decltype(&T::m) waldo(T t);
|
||||
//
|
||||
// void test() {
|
||||
// waldo(A());
|
||||
// }
|
||||
public void testAddressOfMethodUntargeted_509396() throws Exception {
|
||||
parseAndCheckBindings();
|
||||
}
|
||||
|
||||
// template<typename T, unsigned length> struct Templ {
|
||||
// Templ(){}
|
||||
// };
|
||||
|
|
|
@ -254,7 +254,7 @@ public class CPPASTFunctionCallExpression extends ASTNode
|
|||
LookupData data= CPPSemantics.createLookupData(((IASTIdExpression) fFunctionName).getName());
|
||||
try {
|
||||
ICPPConstructor[] constructors = ClassTypeHelper.getConstructors(cls, data.getLookupPoint());
|
||||
IBinding b= CPPSemantics.resolveFunction(data, constructors, true);
|
||||
IBinding b= CPPSemantics.resolveFunction(data, constructors, true, false);
|
||||
if (b instanceof ICPPFunction)
|
||||
return (ICPPFunction) b;
|
||||
} catch (DOMException e) {
|
||||
|
|
|
@ -198,6 +198,7 @@ import org.eclipse.cdt.internal.core.dom.parser.ASTQueries;
|
|||
import org.eclipse.cdt.internal.core.dom.parser.IASTAmbiguousDeclarator;
|
||||
import org.eclipse.cdt.internal.core.dom.parser.IASTInternalScope;
|
||||
import org.eclipse.cdt.internal.core.dom.parser.IRecursionResolvingBinding;
|
||||
import org.eclipse.cdt.internal.core.dom.parser.ITypeContainer;
|
||||
import org.eclipse.cdt.internal.core.dom.parser.IntegralValue;
|
||||
import org.eclipse.cdt.internal.core.dom.parser.ProblemBinding;
|
||||
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTIdExpression;
|
||||
|
@ -478,7 +479,7 @@ public class CPPSemantics {
|
|||
// Do not interpret template arguments to a template class as being
|
||||
// explicit template arguments to its templated constructor.
|
||||
data.setTemplateArguments(null);
|
||||
binding= resolveFunction(data, ClassTypeHelper.getConstructors(cls, lookupPoint), true);
|
||||
binding= resolveFunction(data, ClassTypeHelper.getConstructors(cls, lookupPoint), true, false);
|
||||
}
|
||||
} catch (DOMException e) {
|
||||
return e.getProblem();
|
||||
|
@ -2289,7 +2290,7 @@ public class CPPSemantics {
|
|||
return obj;
|
||||
}
|
||||
}
|
||||
return resolveFunction(data, fnArray, true);
|
||||
return resolveFunction(data, fnArray, true, false);
|
||||
}
|
||||
|
||||
if (obj != null) {
|
||||
|
@ -2560,7 +2561,8 @@ public class CPPSemantics {
|
|||
return result;
|
||||
}
|
||||
|
||||
public static IBinding resolveFunction(LookupData data, ICPPFunction[] fns, boolean allowUDC) throws DOMException {
|
||||
public static IBinding resolveFunction(LookupData data, ICPPFunction[] fns, boolean allowUDC,
|
||||
boolean resolveTargetedArgumentTypes) throws DOMException {
|
||||
final IASTName lookupName = data.getLookupName();
|
||||
if (fns == null || fns.length == 0 || fns[0] == null)
|
||||
return null;
|
||||
|
@ -2585,7 +2587,7 @@ public class CPPSemantics {
|
|||
return createFunctionSet(fns, data.getTemplateArguments(), lookupPoint, lookupName);
|
||||
}
|
||||
|
||||
// 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.
|
||||
final IType[] argTypes = data.getFunctionArgumentTypes();
|
||||
ICPPFunction[] tmp= selectByArgumentCount(data, fns);
|
||||
if (tmp.length == 0 || tmp[0] == null)
|
||||
|
@ -2631,7 +2633,7 @@ public class CPPSemantics {
|
|||
continue;
|
||||
|
||||
UDCMode udc = allowUDC ? UDCMode.DEFER : UDCMode.FORBIDDEN;
|
||||
final FunctionCost fnCost= costForFunctionCall(fn, udc, data);
|
||||
FunctionCost fnCost= costForFunctionCall(fn, udc, data, resolveTargetedArgumentTypes);
|
||||
if (fnCost == null)
|
||||
continue;
|
||||
|
||||
|
@ -2706,6 +2708,37 @@ public class CPPSemantics {
|
|||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* If {@code type} is a {@link FunctionSetType} or a pointer type containing a FunctionSetType,
|
||||
* resolves the FunctionSetType using the given target type.
|
||||
*
|
||||
* @param type the type to resolve
|
||||
* @param targetType the target type
|
||||
* @param point the name lookup context
|
||||
* @return the resolved type, or the given {@type} if the type didn't contain a FunctionSetType
|
||||
* or the targeted function resolution failed
|
||||
*/
|
||||
private static IType resolveTargetedFunctionSetType(IType type, IType targetType, IASTNode point) {
|
||||
IType t = type;
|
||||
if (type instanceof IPointerType) {
|
||||
t = ((IPointerType) type).getType();
|
||||
}
|
||||
|
||||
if (t instanceof FunctionSetType) {
|
||||
ICPPFunction function =
|
||||
resolveTargetedFunction(targetType, ((FunctionSetType) t).getFunctionSet(), point);
|
||||
if (function != null && !(function instanceof IProblemBinding)) {
|
||||
type = function.getType();
|
||||
if (targetType instanceof ITypeContainer) {
|
||||
ITypeContainer containerType = (ITypeContainer) targetType.clone();
|
||||
containerType.setType(type);
|
||||
type = containerType;
|
||||
}
|
||||
}
|
||||
}
|
||||
return type;
|
||||
}
|
||||
|
||||
private static IBinding createFunctionSet(ICPPFunction[] fns, ICPPTemplateArgument[] args, IASTNode point, IASTName name) {
|
||||
// First try to find a unique function
|
||||
if (name != null && name.getPropertyInParent() == ICPPASTTemplateId.TEMPLATE_NAME) {
|
||||
|
@ -2861,15 +2894,35 @@ public class CPPSemantics {
|
|||
}
|
||||
}
|
||||
|
||||
private static FunctionCost costForFunctionCall(ICPPFunction fn, UDCMode udc, LookupData data)
|
||||
throws DOMException {
|
||||
IType[] argTypes= data.getFunctionArgumentTypes();
|
||||
ValueCategory[] argValueCategories= data.getFunctionArgumentValueCategories();
|
||||
int skipArg= 0;
|
||||
private static FunctionCost costForFunctionCall(ICPPFunction fn, UDCMode udc, LookupData data,
|
||||
boolean resolveTargetedArgumentTypes) throws DOMException {
|
||||
final ICPPFunctionType ftype= fn.getType();
|
||||
if (ftype == null)
|
||||
return null;
|
||||
|
||||
IType[] argTypes= data.getFunctionArgumentTypes();
|
||||
ValueCategory[] argValueCategories= data.getFunctionArgumentValueCategories();
|
||||
if (resolveTargetedArgumentTypes) {
|
||||
IType[] newArgTypes = null;
|
||||
IType[] paramTypes = fn.getType().getParameterTypes();
|
||||
for (int i = 0; i < argTypes.length && i < paramTypes.length; i++) {
|
||||
IType argType = argTypes[i];
|
||||
IType paramType = paramTypes[i];
|
||||
IType newArgType = resolveTargetedFunctionSetType(argType, paramType, data.getLookupPoint());
|
||||
if (newArgType != argType) {
|
||||
if (newArgTypes == null) {
|
||||
newArgTypes = new IType[argTypes.length];
|
||||
System.arraycopy(argTypes, 0, newArgTypes, 0, argTypes.length);
|
||||
}
|
||||
newArgTypes[i] = newArgType;
|
||||
}
|
||||
}
|
||||
if (newArgTypes != null) {
|
||||
argTypes = newArgTypes;
|
||||
}
|
||||
}
|
||||
|
||||
int skipArg= 0;
|
||||
IType implicitParameterType= null;
|
||||
IType impliedObjectType= null;
|
||||
ValueCategory impliedObjectValueCategory= null;
|
||||
|
@ -3087,7 +3140,7 @@ public class CPPSemantics {
|
|||
data.setFunctionArguments(false, init.getArguments());
|
||||
try {
|
||||
IBinding ctor = resolveFunction(data,
|
||||
ClassTypeHelper.getConstructors((ICPPClassType) targetType, name), true);
|
||||
ClassTypeHelper.getConstructors((ICPPClassType) targetType, name), true, false);
|
||||
if (ctor instanceof ICPPConstructor) {
|
||||
int i= 0;
|
||||
for (IASTNode arg : init.getArguments()) {
|
||||
|
@ -3268,7 +3321,7 @@ public class CPPSemantics {
|
|||
*/
|
||||
CPPBasicType t = new CPPBasicType(Kind.eInt, IBasicType.IS_UNSIGNED | IBasicType.IS_LONG_LONG, exp);
|
||||
data.setFunctionArguments(false, createArgForType(exp, t));
|
||||
ret = resolveFunction(data, funcs, true);
|
||||
ret = resolveFunction(data, funcs, true, false);
|
||||
if (isViableUserDefinedLiteralOperator(ret, kind)) {
|
||||
return ret;
|
||||
}
|
||||
|
@ -3282,7 +3335,7 @@ public class CPPSemantics {
|
|||
*/
|
||||
CPPBasicType t = new CPPBasicType(Kind.eDouble, IBasicType.IS_LONG, exp);
|
||||
data.setFunctionArguments(false, createArgForType(exp, t));
|
||||
ret = resolveFunction(data, funcs, true);
|
||||
ret = resolveFunction(data, funcs, true, false);
|
||||
if (isViableUserDefinedLiteralOperator(ret, kind)) {
|
||||
return ret;
|
||||
}
|
||||
|
@ -3297,7 +3350,7 @@ public class CPPSemantics {
|
|||
CPPPointerType charArray = new CPPPointerType(CPPBasicType.CHAR, true, false, false);
|
||||
data = new LookupData(((CPPASTLiteralExpression) exp).getOperatorName(), null, exp);
|
||||
data.setFunctionArguments(false, createArgForType(exp, charArray));
|
||||
ret = resolveFunction(data, funcs, true);
|
||||
ret = resolveFunction(data, funcs, true, false);
|
||||
|
||||
//
|
||||
char[] stringLiteral = exp.getValue(); // The string literal that was passed to the operator
|
||||
|
@ -3310,7 +3363,7 @@ public class CPPSemantics {
|
|||
}
|
||||
|
||||
data = new LookupData(((CPPASTLiteralExpression) exp).getOperatorName(), args, exp);
|
||||
IBinding litTpl = resolveFunction(data, tplFunctions, true);
|
||||
IBinding litTpl = resolveFunction(data, tplFunctions, true, false);
|
||||
|
||||
// Do we have valid template and non-template bindings?
|
||||
if (ret != null && !(ret instanceof IProblemBinding)) {
|
||||
|
@ -3342,7 +3395,7 @@ public class CPPSemantics {
|
|||
createArgForType(null, CPPBasicType.UNSIGNED_INT)
|
||||
};
|
||||
data.setFunctionArguments(false, initializer);
|
||||
ret = resolveFunction(data, funcs, true);
|
||||
ret = resolveFunction(data, funcs, true, false);
|
||||
} else if (kind == IASTLiteralExpression.lk_char_constant) {
|
||||
/*
|
||||
* 2.14.8.6
|
||||
|
@ -3353,12 +3406,16 @@ public class CPPSemantics {
|
|||
*/
|
||||
CPPBasicType t = new CPPBasicType(((CPPASTLiteralExpression) exp).getBasicCharKind(), 0, exp);
|
||||
data.setFunctionArguments(false, createArgForType(exp, t));
|
||||
ret = resolveFunction(data, funcs, true);
|
||||
ret = resolveFunction(data, funcs, true, false);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* 13.4-1 A use of an overloaded function without arguments is resolved in certain contexts to
|
||||
* a function.
|
||||
*/
|
||||
static ICPPFunction resolveTargetedFunction(IType targetType, CPPFunctionSet set, IASTNode point) {
|
||||
targetType= getNestedType(targetType, TDEF | REF | CVTYPE | PTR | MPTR);
|
||||
if (!(targetType instanceof ICPPFunctionType))
|
||||
|
|
|
@ -17,7 +17,9 @@ package org.eclipse.cdt.internal.core.dom.parser.cpp.semantics;
|
|||
|
||||
import static org.eclipse.cdt.core.dom.ast.IASTExpression.ValueCategory.LVALUE;
|
||||
import static org.eclipse.cdt.internal.core.dom.parser.cpp.InstantiationContext.getContextClassSpecialization;
|
||||
import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.ALLCVQ;
|
||||
import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.CVTYPE;
|
||||
import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.REF;
|
||||
import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.TDEF;
|
||||
import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.getNestedType;
|
||||
|
||||
|
@ -2276,7 +2278,7 @@ public class CPPTemplates {
|
|||
IBinding instance= instantiateFunctionTemplate(template, args, map, point);
|
||||
if (instance instanceof ICPPFunction) {
|
||||
final ICPPFunction f = (ICPPFunction) instance;
|
||||
if (SemanticUtil.isValidType(f.getType())) {
|
||||
if (isValidFunctionType(f.getType())) {
|
||||
// The number of arguments have been checked against the function
|
||||
// template's required argument count at an earlier stage. However,
|
||||
// the process of instantiation can increase the required argument
|
||||
|
@ -2294,6 +2296,22 @@ public class CPPTemplates {
|
|||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the given function type is problem-free and that the return type is not a function set.
|
||||
*/
|
||||
public static boolean isValidFunctionType(IFunctionType type) {
|
||||
if (!SemanticUtil.isValidType(type))
|
||||
return false;
|
||||
|
||||
IType t = type.getReturnType();
|
||||
t = SemanticUtil.getNestedType(t, ALLCVQ | TDEF | REF);
|
||||
if (t instanceof IPointerType)
|
||||
t = ((IPointerType) t).getType();
|
||||
if (t instanceof FunctionSetType)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 14.8.2.3 Deducing conversion function template arguments
|
||||
* @param point
|
||||
|
|
|
@ -716,7 +716,7 @@ public class Conversions {
|
|||
}
|
||||
}
|
||||
}
|
||||
final IBinding result= CPPSemantics.resolveFunction(data, filteredConstructors, true);
|
||||
final IBinding result= CPPSemantics.resolveFunction(data, filteredConstructors, true, false);
|
||||
final Cost c;
|
||||
if (result instanceof ICPPMethod) {
|
||||
c= new Cost(arg.getType(point), t, Rank.IDENTITY);
|
||||
|
|
|
@ -338,7 +338,7 @@ public class EvalFunctionSet extends CPPDependentEvaluation {
|
|||
}
|
||||
|
||||
// Perform template instantiation and overload resolution.
|
||||
IBinding binding = CPPSemantics.resolveFunction(data, functions, true);
|
||||
IBinding binding = CPPSemantics.resolveFunction(data, functions, true, true);
|
||||
if (binding == null || binding instanceof IProblemBinding)
|
||||
return EvalFixed.INCOMPLETE;
|
||||
if (binding instanceof ICPPFunction && !(binding instanceof ICPPUnknownBinding))
|
||||
|
|
|
@ -282,7 +282,7 @@ public class EvalTypeId extends CPPDependentEvaluation {
|
|||
data.foundItems = constructors;
|
||||
data.setFunctionArguments(false, arguments);
|
||||
try {
|
||||
IBinding binding = CPPSemantics.resolveFunction(data, constructors, true);
|
||||
IBinding binding = CPPSemantics.resolveFunction(data, constructors, true, false);
|
||||
if (binding instanceof ICPPFunction) {
|
||||
return (ICPPFunction) binding;
|
||||
}
|
||||
|
|
|
@ -1082,7 +1082,7 @@ public class BindingClassifier {
|
|||
lookupData.setFunctionArguments(false, new IASTInitializerClause[] { argument });
|
||||
lookupData.qualified = true;
|
||||
try {
|
||||
IBinding constructor = CPPSemantics.resolveFunction(lookupData, ClassTypeHelper.getConstructors(classType, argument), false);
|
||||
IBinding constructor = CPPSemantics.resolveFunction(lookupData, ClassTypeHelper.getConstructors(classType, argument), false, false);
|
||||
if (constructor instanceof ICPPConstructor && !((ICPPConstructor) constructor).isExplicit())
|
||||
return true;
|
||||
} catch (DOMException e) {
|
||||
|
|
Loading…
Add table
Reference in a new issue