1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-07-21 07:55:24 +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:
Sergey Prigogin 2017-03-10 16:30:24 -08:00 committed by Gerrit Code Review @ Eclipse.org
parent 8bfd2cdc22
commit 8da53f1e5e
8 changed files with 135 additions and 23 deletions

View file

@ -5969,6 +5969,43 @@ public class AST2TemplateTests extends AST2TestBase {
parseAndCheckBindings(); 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 { // template<typename T, unsigned length> struct Templ {
// Templ(){} // Templ(){}
// }; // };

View file

@ -254,7 +254,7 @@ public class CPPASTFunctionCallExpression extends ASTNode
LookupData data= CPPSemantics.createLookupData(((IASTIdExpression) fFunctionName).getName()); LookupData data= CPPSemantics.createLookupData(((IASTIdExpression) fFunctionName).getName());
try { try {
ICPPConstructor[] constructors = ClassTypeHelper.getConstructors(cls, data.getLookupPoint()); 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) if (b instanceof ICPPFunction)
return (ICPPFunction) b; return (ICPPFunction) b;
} catch (DOMException e) { } catch (DOMException e) {

View file

@ -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.IASTAmbiguousDeclarator;
import org.eclipse.cdt.internal.core.dom.parser.IASTInternalScope; 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.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.IntegralValue;
import org.eclipse.cdt.internal.core.dom.parser.ProblemBinding; import org.eclipse.cdt.internal.core.dom.parser.ProblemBinding;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTIdExpression; 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 // Do not interpret template arguments to a template class as being
// explicit template arguments to its templated constructor. // explicit template arguments to its templated constructor.
data.setTemplateArguments(null); data.setTemplateArguments(null);
binding= resolveFunction(data, ClassTypeHelper.getConstructors(cls, lookupPoint), true); binding= resolveFunction(data, ClassTypeHelper.getConstructors(cls, lookupPoint), true, false);
} }
} catch (DOMException e) { } catch (DOMException e) {
return e.getProblem(); return e.getProblem();
@ -2289,7 +2290,7 @@ public class CPPSemantics {
return obj; return obj;
} }
} }
return resolveFunction(data, fnArray, true); return resolveFunction(data, fnArray, true, false);
} }
if (obj != null) { if (obj != null) {
@ -2560,7 +2561,8 @@ public class CPPSemantics {
return result; 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(); final IASTName lookupName = data.getLookupName();
if (fns == null || fns.length == 0 || fns[0] == null) if (fns == null || fns.length == 0 || fns[0] == null)
return null; return null;
@ -2585,7 +2587,7 @@ public class CPPSemantics {
return createFunctionSet(fns, data.getTemplateArguments(), lookupPoint, lookupName); 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(); final IType[] argTypes = data.getFunctionArgumentTypes();
ICPPFunction[] tmp= selectByArgumentCount(data, fns); ICPPFunction[] tmp= selectByArgumentCount(data, fns);
if (tmp.length == 0 || tmp[0] == null) if (tmp.length == 0 || tmp[0] == null)
@ -2631,7 +2633,7 @@ public class CPPSemantics {
continue; continue;
UDCMode udc = allowUDC ? UDCMode.DEFER : UDCMode.FORBIDDEN; UDCMode udc = allowUDC ? UDCMode.DEFER : UDCMode.FORBIDDEN;
final FunctionCost fnCost= costForFunctionCall(fn, udc, data); FunctionCost fnCost= costForFunctionCall(fn, udc, data, resolveTargetedArgumentTypes);
if (fnCost == null) if (fnCost == null)
continue; continue;
@ -2706,6 +2708,37 @@ public class CPPSemantics {
return result; 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) { private static IBinding createFunctionSet(ICPPFunction[] fns, ICPPTemplateArgument[] args, IASTNode point, IASTName name) {
// First try to find a unique function // First try to find a unique function
if (name != null && name.getPropertyInParent() == ICPPASTTemplateId.TEMPLATE_NAME) { 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) private static FunctionCost costForFunctionCall(ICPPFunction fn, UDCMode udc, LookupData data,
throws DOMException { boolean resolveTargetedArgumentTypes) throws DOMException {
IType[] argTypes= data.getFunctionArgumentTypes();
ValueCategory[] argValueCategories= data.getFunctionArgumentValueCategories();
int skipArg= 0;
final ICPPFunctionType ftype= fn.getType(); final ICPPFunctionType ftype= fn.getType();
if (ftype == null) if (ftype == null)
return 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 implicitParameterType= null;
IType impliedObjectType= null; IType impliedObjectType= null;
ValueCategory impliedObjectValueCategory= null; ValueCategory impliedObjectValueCategory= null;
@ -3087,7 +3140,7 @@ public class CPPSemantics {
data.setFunctionArguments(false, init.getArguments()); data.setFunctionArguments(false, init.getArguments());
try { try {
IBinding ctor = resolveFunction(data, IBinding ctor = resolveFunction(data,
ClassTypeHelper.getConstructors((ICPPClassType) targetType, name), true); ClassTypeHelper.getConstructors((ICPPClassType) targetType, name), true, false);
if (ctor instanceof ICPPConstructor) { if (ctor instanceof ICPPConstructor) {
int i= 0; int i= 0;
for (IASTNode arg : init.getArguments()) { 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); CPPBasicType t = new CPPBasicType(Kind.eInt, IBasicType.IS_UNSIGNED | IBasicType.IS_LONG_LONG, exp);
data.setFunctionArguments(false, createArgForType(exp, t)); data.setFunctionArguments(false, createArgForType(exp, t));
ret = resolveFunction(data, funcs, true); ret = resolveFunction(data, funcs, true, false);
if (isViableUserDefinedLiteralOperator(ret, kind)) { if (isViableUserDefinedLiteralOperator(ret, kind)) {
return ret; return ret;
} }
@ -3282,7 +3335,7 @@ public class CPPSemantics {
*/ */
CPPBasicType t = new CPPBasicType(Kind.eDouble, IBasicType.IS_LONG, exp); CPPBasicType t = new CPPBasicType(Kind.eDouble, IBasicType.IS_LONG, exp);
data.setFunctionArguments(false, createArgForType(exp, t)); data.setFunctionArguments(false, createArgForType(exp, t));
ret = resolveFunction(data, funcs, true); ret = resolveFunction(data, funcs, true, false);
if (isViableUserDefinedLiteralOperator(ret, kind)) { if (isViableUserDefinedLiteralOperator(ret, kind)) {
return ret; return ret;
} }
@ -3297,7 +3350,7 @@ public class CPPSemantics {
CPPPointerType charArray = new CPPPointerType(CPPBasicType.CHAR, true, false, false); CPPPointerType charArray = new CPPPointerType(CPPBasicType.CHAR, true, false, false);
data = new LookupData(((CPPASTLiteralExpression) exp).getOperatorName(), null, exp); data = new LookupData(((CPPASTLiteralExpression) exp).getOperatorName(), null, exp);
data.setFunctionArguments(false, createArgForType(exp, charArray)); 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 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); 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? // Do we have valid template and non-template bindings?
if (ret != null && !(ret instanceof IProblemBinding)) { if (ret != null && !(ret instanceof IProblemBinding)) {
@ -3342,7 +3395,7 @@ public class CPPSemantics {
createArgForType(null, CPPBasicType.UNSIGNED_INT) createArgForType(null, CPPBasicType.UNSIGNED_INT)
}; };
data.setFunctionArguments(false, initializer); data.setFunctionArguments(false, initializer);
ret = resolveFunction(data, funcs, true); ret = resolveFunction(data, funcs, true, false);
} else if (kind == IASTLiteralExpression.lk_char_constant) { } else if (kind == IASTLiteralExpression.lk_char_constant) {
/* /*
* 2.14.8.6 * 2.14.8.6
@ -3353,12 +3406,16 @@ public class CPPSemantics {
*/ */
CPPBasicType t = new CPPBasicType(((CPPASTLiteralExpression) exp).getBasicCharKind(), 0, exp); CPPBasicType t = new CPPBasicType(((CPPASTLiteralExpression) exp).getBasicCharKind(), 0, exp);
data.setFunctionArguments(false, createArgForType(exp, t)); data.setFunctionArguments(false, createArgForType(exp, t));
ret = resolveFunction(data, funcs, true); ret = resolveFunction(data, funcs, true, false);
} }
return ret; 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) { static ICPPFunction resolveTargetedFunction(IType targetType, CPPFunctionSet set, IASTNode point) {
targetType= getNestedType(targetType, TDEF | REF | CVTYPE | PTR | MPTR); targetType= getNestedType(targetType, TDEF | REF | CVTYPE | PTR | MPTR);
if (!(targetType instanceof ICPPFunctionType)) if (!(targetType instanceof ICPPFunctionType))

View file

@ -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.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.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.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.TDEF;
import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.getNestedType; 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); IBinding instance= instantiateFunctionTemplate(template, args, map, point);
if (instance instanceof ICPPFunction) { if (instance instanceof ICPPFunction) {
final ICPPFunction f = (ICPPFunction) instance; final ICPPFunction f = (ICPPFunction) instance;
if (SemanticUtil.isValidType(f.getType())) { if (isValidFunctionType(f.getType())) {
// The number of arguments have been checked against the function // The number of arguments have been checked against the function
// template's required argument count at an earlier stage. However, // template's required argument count at an earlier stage. However,
// the process of instantiation can increase the required argument // the process of instantiation can increase the required argument
@ -2294,6 +2296,22 @@ public class CPPTemplates {
return null; 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 * 14.8.2.3 Deducing conversion function template arguments
* @param point * @param point

View file

@ -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; final Cost c;
if (result instanceof ICPPMethod) { if (result instanceof ICPPMethod) {
c= new Cost(arg.getType(point), t, Rank.IDENTITY); c= new Cost(arg.getType(point), t, Rank.IDENTITY);

View file

@ -338,7 +338,7 @@ public class EvalFunctionSet extends CPPDependentEvaluation {
} }
// Perform template instantiation and overload resolution. // 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) if (binding == null || binding instanceof IProblemBinding)
return EvalFixed.INCOMPLETE; return EvalFixed.INCOMPLETE;
if (binding instanceof ICPPFunction && !(binding instanceof ICPPUnknownBinding)) if (binding instanceof ICPPFunction && !(binding instanceof ICPPUnknownBinding))

View file

@ -282,7 +282,7 @@ public class EvalTypeId extends CPPDependentEvaluation {
data.foundItems = constructors; data.foundItems = constructors;
data.setFunctionArguments(false, arguments); data.setFunctionArguments(false, arguments);
try { try {
IBinding binding = CPPSemantics.resolveFunction(data, constructors, true); IBinding binding = CPPSemantics.resolveFunction(data, constructors, true, false);
if (binding instanceof ICPPFunction) { if (binding instanceof ICPPFunction) {
return (ICPPFunction) binding; return (ICPPFunction) binding;
} }

View file

@ -1082,7 +1082,7 @@ public class BindingClassifier {
lookupData.setFunctionArguments(false, new IASTInitializerClause[] { argument }); lookupData.setFunctionArguments(false, new IASTInitializerClause[] { argument });
lookupData.qualified = true; lookupData.qualified = true;
try { 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()) if (constructor instanceof ICPPConstructor && !((ICPPConstructor) constructor).isExplicit())
return true; return true;
} catch (DOMException e) { } catch (DOMException e) {