diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2TemplateTests.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2TemplateTests.java index f64cd23ef1a..6e32e8aa394 100644 --- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2TemplateTests.java +++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2TemplateTests.java @@ -5969,6 +5969,43 @@ public class AST2TemplateTests extends AST2TestBase { parseAndCheckBindings(); } + // struct A { + // template + // void m(U); + // int m(int); + // }; + // + // void foo(void(A::*)(int)); + // void foo(int); + // + // template + // decltype(foo(&T::m)) waldo(T); + // + // int main() { + // waldo(A()); + // } + public void testAddressOfMethodTargeted_509396() throws Exception { + parseAndCheckBindings(); + } + + // struct A { + // template + // void m(U t); + // }; + // + // template + // void waldo(T t); + // + // template + // decltype(&T::m) waldo(T t); + // + // void test() { + // waldo(A()); + // } + public void testAddressOfMethodUntargeted_509396() throws Exception { + parseAndCheckBindings(); + } + // template struct Templ { // Templ(){} // }; diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTFunctionCallExpression.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTFunctionCallExpression.java index 840e8f76618..a17a162ee95 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTFunctionCallExpression.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTFunctionCallExpression.java @@ -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) { diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPSemantics.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPSemantics.java index 0bc2bf0b067..f3892f091a4 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPSemantics.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPSemantics.java @@ -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)) diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPTemplates.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPTemplates.java index 7db1e49d94a..7d35f33ce15 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPTemplates.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPTemplates.java @@ -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 diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/Conversions.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/Conversions.java index fa543be098e..3691efb0202 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/Conversions.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/Conversions.java @@ -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); diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalFunctionSet.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalFunctionSet.java index 2ad68300930..824e99a4274 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalFunctionSet.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalFunctionSet.java @@ -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)) diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalTypeId.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalTypeId.java index 910eb1d95b4..af9a18cfa98 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalTypeId.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalTypeId.java @@ -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; } diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/includes/BindingClassifier.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/includes/BindingClassifier.java index 7e189b61fab..5c7fa4e546f 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/includes/BindingClassifier.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/includes/BindingClassifier.java @@ -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) {