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 9d6a65a6de9..3dc6e481ff0 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 @@ -7539,10 +7539,47 @@ public class AST2TemplateTests extends AST2TestBase { // void foo(T t) { // bar(t); // } - public void testUnqualifiedFunctionCallInTemplate_402498() throws Exception { + public void testUnqualifiedFunctionCallInTemplate_402498a() throws Exception { parseAndCheckBindings(); } + // template + // auto foo(T t) -> decltype(bar(t)); + // + // namespace N { + // class A {}; + // int bar(A); + // } + // + // int main() { + // auto x = foo(N::A()); + // } + public void testUnqualifiedFunctionCallInTemplate_402498b() throws Exception { + new BindingAssertionHelper(getAboveComment(), true).assertVariableType("x", CommonTypes.int_); + } + + // template + // auto foo(T t) -> decltype(bar(t)); + // + // namespace N { + // class A {}; + // } + // + // int bar(A); + // + // int main() { + // auto x = foo(N::A()); + // } + public void testUnqualifiedFunctionCallInTemplate_402498c() throws Exception { + BindingAssertionHelper helper = new BindingAssertionHelper(getAboveComment(), true); + ICPPVariable x = helper.assertNonProblem("x", ICPPVariable.class); + // We really should assert that x's type is a ProblemType, but the semantic + // analyzer is too lenient and makes it a TypeOfDependentExpression if it + // can't instantiate the return type of foo() properly. + // That's another bug for another day. + assertFalse(x.getType().isSameType(CommonTypes.int_)); + } + // template // struct no_type {}; // diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPDeferredFunction.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPDeferredFunction.java index a9902441692..6f56b9210a9 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPDeferredFunction.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPDeferredFunction.java @@ -28,7 +28,6 @@ import org.eclipse.cdt.internal.core.dom.parser.ProblemType; public class CPPDeferredFunction extends CPPUnknownBinding implements ICPPFunction, ICPPComputableFunction { private static final ICPPFunctionType FUNCTION_TYPE= new CPPFunctionType(ProblemType.UNKNOWN_FOR_EXPRESSION, IType.EMPTY_TYPE_ARRAY); - private static final ICPPFunction[] NO_CANDIDATES= {}; /** * Creates a CPPDeferredFunction given a set of overloaded functions @@ -52,7 +51,7 @@ public class CPPDeferredFunction extends CPPUnknownBinding implements ICPPFuncti * @return the constructed CPPDeferredFunction */ public static ICPPFunction createForName(char[] name) { - return new CPPDeferredFunction(null, name, NO_CANDIDATES); + return new CPPDeferredFunction(null, name, null); } private final IBinding fOwner; 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 6dd5c3bab52..b744feffa86 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 @@ -562,8 +562,12 @@ public class CPPSemantics { return false; } - private static void doKoenigLookup(LookupData data) throws DOMException { + public static void doKoenigLookup(LookupData data) throws DOMException { data.ignoreUsingDirectives = true; + // Set 'qualified' to true for the duration of this function call + // so the calls to lookup() don't ascend into enclosing scopes. + boolean originalQualified = data.qualified; + data.qualified = true; Set friendFns = new HashSet(2); Set associated = getAssociatedScopes(data, friendFns); for (ICPPNamespaceScope scope : associated) { @@ -572,6 +576,7 @@ public class CPPSemantics { } } mergeResults(data, friendFns.toArray(), false); + data.qualified = originalQualified; } static IBinding checkDeclSpecifier(IBinding binding, IASTName name, IASTNode decl) { 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 9597fa30445..501ba428afe 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 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2012 Wind River Systems, Inc. and others. + * Copyright (c) 2012, 2013 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 @@ -28,6 +28,7 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassTemplate; import org.eclipse.cdt.core.dom.ast.cpp.ICPPFunction; import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateArgument; import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateParameterMap; +import org.eclipse.cdt.core.parser.util.ArrayUtil; import org.eclipse.cdt.internal.core.dom.parser.ISerializableEvaluation; import org.eclipse.cdt.internal.core.dom.parser.ITypeMarshalBuffer; import org.eclipse.cdt.internal.core.dom.parser.Value; @@ -46,21 +47,41 @@ public class EvalFunctionSet extends CPPDependentEvaluation { // the type of 'obj' (needed for correct overload resolution of 'member_function' later). // Otherwise null. private final IType fImpliedObjectType; + + // Used to represent an EvalFunctionSet with zero functions. + // (We need the name in resolveFunction() - usually we get it from the CPPFunctionSet + // by asking the first function in the set for its name.) + // Exactly one of fFunctionSet and fName should be non-null. + private final char[] fName; public EvalFunctionSet(CPPFunctionSet set, boolean addressOf, IType impliedObjectType, IASTNode pointOfDefinition) { this(set, addressOf, impliedObjectType, findEnclosingTemplate(pointOfDefinition)); } + public EvalFunctionSet(CPPFunctionSet set, boolean addressOf, IType impliedObjectType, IBinding templateDefinition) { super(templateDefinition); fFunctionSet= set; fAddressOf= addressOf; fImpliedObjectType= impliedObjectType; + fName= null; + } + + public EvalFunctionSet(char[] name, boolean addressOf, IASTNode pointOfDefinition) { + this(name, addressOf, findEnclosingTemplate(pointOfDefinition)); + } + + public EvalFunctionSet(char[] name, boolean addressOf, IBinding templateDefinition) { + super(templateDefinition); + fFunctionSet= null; + fAddressOf= addressOf; + fImpliedObjectType= null; + fName= name; } public CPPFunctionSet getFunctionSet() { return fFunctionSet; } - + public boolean isAddressOf() { return fAddressOf; } @@ -81,6 +102,8 @@ public class EvalFunctionSet extends CPPDependentEvaluation { @Override public boolean isTypeDependent() { + if (fFunctionSet == null) + return true; final ICPPTemplateArgument[] args = fFunctionSet.getTemplateArguments(); if (args != null) { for (ICPPTemplateArgument arg : args) { @@ -115,54 +138,74 @@ public class EvalFunctionSet extends CPPDependentEvaluation { return PRVALUE; } + // Descriptive names for flags used during serialization. + private final static short FLAG_ADDRESS_OF = ITypeMarshalBuffer.FLAG1; + private final static short FLAG_HAS_FUNCTION_SET = ITypeMarshalBuffer.FLAG2; + private final static short FLAG_HAS_TEMPLATE_ARGS = ITypeMarshalBuffer.FLAG3; + @Override public void marshal(ITypeMarshalBuffer buffer, boolean includeValue) throws CoreException { - final ICPPFunction[] bindings = fFunctionSet.getBindings(); - final ICPPTemplateArgument[] args = fFunctionSet.getTemplateArguments(); short firstBytes = ITypeMarshalBuffer.EVAL_FUNCTION_SET; if (fAddressOf) - firstBytes |= ITypeMarshalBuffer.FLAG1; - if (args != null) - firstBytes |= ITypeMarshalBuffer.FLAG2; + firstBytes |= FLAG_ADDRESS_OF; + if (fFunctionSet != null) { + firstBytes |= FLAG_HAS_FUNCTION_SET; + final ICPPFunction[] bindings = fFunctionSet.getBindings(); + final ICPPTemplateArgument[] args = fFunctionSet.getTemplateArguments(); + if (args != null) + firstBytes |= FLAG_HAS_TEMPLATE_ARGS; - buffer.putShort(firstBytes); - buffer.putInt(bindings.length); - for (ICPPFunction binding : bindings) { - buffer.marshalBinding(binding); - } - if (args != null) { - buffer.putInt(args.length); - for (ICPPTemplateArgument arg : args) { - buffer.marshalTemplateArgument(arg); + buffer.putShort(firstBytes); + buffer.putInt(bindings.length); + for (ICPPFunction binding : bindings) { + buffer.marshalBinding(binding); } + if (args != null) { + buffer.putInt(args.length); + for (ICPPTemplateArgument arg : args) { + buffer.marshalTemplateArgument(arg); + } + } + buffer.marshalType(fImpliedObjectType); + } else { + buffer.putShort(firstBytes); + buffer.putCharArray(fName); } - buffer.marshalType(fImpliedObjectType); marshalTemplateDefinition(buffer); } public static ISerializableEvaluation unmarshal(short firstBytes, ITypeMarshalBuffer buffer) throws CoreException { - final boolean addressOf= (firstBytes & ITypeMarshalBuffer.FLAG1) != 0; - int bindingCount= buffer.getInt(); - ICPPFunction[] bindings= new ICPPFunction[bindingCount]; - for (int i = 0; i < bindings.length; i++) { - bindings[i]= (ICPPFunction) buffer.unmarshalBinding(); - } - ICPPTemplateArgument[] args= null; - if ((firstBytes & ITypeMarshalBuffer.FLAG2) != 0) { - int len= buffer.getInt(); - args = new ICPPTemplateArgument[len]; - for (int i = 0; i < args.length; i++) { - args[i]= buffer.unmarshalTemplateArgument(); + final boolean addressOf= (firstBytes & FLAG_ADDRESS_OF) != 0; + if ((firstBytes & FLAG_HAS_FUNCTION_SET) != 0) { + int bindingCount= buffer.getInt(); + ICPPFunction[] bindings= new ICPPFunction[bindingCount]; + for (int i = 0; i < bindings.length; i++) { + bindings[i]= (ICPPFunction) buffer.unmarshalBinding(); } + ICPPTemplateArgument[] args= null; + if ((firstBytes & FLAG_HAS_TEMPLATE_ARGS) != 0) { + int len= buffer.getInt(); + args = new ICPPTemplateArgument[len]; + for (int i = 0; i < args.length; i++) { + args[i]= buffer.unmarshalTemplateArgument(); + } + } + IType impliedObjectType= buffer.unmarshalType(); + IBinding templateDefinition= buffer.unmarshalBinding(); + return new EvalFunctionSet(new CPPFunctionSet(bindings, args, null), addressOf, impliedObjectType, templateDefinition); + } else { + char[] name = buffer.getCharArray(); + IBinding templateDefinition= buffer.unmarshalBinding(); + return new EvalFunctionSet(name, addressOf, templateDefinition); } - IType impliedObjectType= buffer.unmarshalType(); - IBinding templateDefinition= buffer.unmarshalBinding(); - return new EvalFunctionSet(new CPPFunctionSet(bindings, args, null), addressOf, impliedObjectType, templateDefinition); } @Override public ICPPEvaluation instantiate(ICPPTemplateParameterMap tpMap, int packOffset, ICPPClassSpecialization within, int maxdepth, IASTNode point) { + if (fFunctionSet == null) + return this; + ICPPTemplateArgument[] originalArguments = fFunctionSet.getTemplateArguments(); ICPPTemplateArgument[] arguments = originalArguments; if (originalArguments != null) @@ -211,13 +254,42 @@ public class EvalFunctionSet extends CPPDependentEvaluation { * succeeded or not */ public ICPPEvaluation resolveFunction(ICPPEvaluation[] args, IASTNode point) { - ICPPFunction[] functions = fFunctionSet.getBindings(); - LookupData data = new LookupData(functions[0].getNameCharArray(), - fFunctionSet.getTemplateArguments(), point); + // Set up the LookupData. + LookupData data; + ICPPFunction[] functions = null; + if (fFunctionSet == null) { + data = new LookupData(fName, null, point); + } else { + functions = fFunctionSet.getBindings(); + data = new LookupData(functions[0].getNameCharArray(), + fFunctionSet.getTemplateArguments(), point); + data.foundItems = functions; + } data.setFunctionArguments(false, args); if (fImpliedObjectType != null) data.setImpliedObjectType(fImpliedObjectType); + try { + // Perform ADL if appropriate. + if (fImpliedObjectType == null && !data.hasTypeOrMemberFunctionOrVariableResult()) { + CPPSemantics.doKoenigLookup(data); + + Object[] foundItems = (Object[]) data.foundItems; + if (foundItems != null && (functions == null || foundItems.length > functions.length)) { + // ADL found additional functions. + functions = Arrays.copyOf(foundItems, foundItems.length, ICPPFunction[].class); + + // doKoenigLookup() may introduce duplicates into the result. These must be + // eliminated to avoid resolveFunction() reporting an ambiguity. (Normally, when + // looukp() and doKoenigLookup() are called on the same LookupData object, the + // two functions coordinate using data stored in that object to eliminate + // duplicates, but in this case lookup() was called before with a different + // LookupData object and now we are only calling doKoenigLookup()). + functions = ArrayUtil.removeDuplicates(functions); + } + } + + // Perform template instantiation and overload resolution. IBinding binding = CPPSemantics.resolveFunction(data, functions, true); if (binding instanceof ICPPFunction && !(binding instanceof ICPPUnknownBinding)) return new EvalBinding(binding, null, getTemplateDefinition()); @@ -230,9 +302,11 @@ public class EvalFunctionSet extends CPPDependentEvaluation { @Override public int determinePackSize(ICPPTemplateParameterMap tpMap) { int r = CPPTemplates.PACK_SIZE_NOT_FOUND; - ICPPTemplateArgument[] templateArguments = fFunctionSet.getTemplateArguments(); - for (ICPPTemplateArgument arg : templateArguments) { - r = CPPTemplates.combinePackSize(r, CPPTemplates.determinePackSize(arg, tpMap)); + if (fFunctionSet != null) { + ICPPTemplateArgument[] templateArguments = fFunctionSet.getTemplateArguments(); + for (ICPPTemplateArgument arg : templateArguments) { + r = CPPTemplates.combinePackSize(r, CPPTemplates.determinePackSize(arg, tpMap)); + } } return r; } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalID.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalID.java index 1a9b23ef992..3e4996d1847 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalID.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalID.java @@ -206,10 +206,13 @@ public class EvalID extends CPPDependentEvaluation { } if (binding instanceof CPPDeferredFunction) { - CPPDeferredFunction deferredFunction = (CPPDeferredFunction) binding; - if (deferredFunction.getCandidates() != null) { - CPPFunctionSet functionSet = new CPPFunctionSet(deferredFunction.getCandidates(), templateArgs, null); + ICPPFunction[] candidates = ((CPPDeferredFunction) binding).getCandidates(); + if (candidates != null) { + CPPFunctionSet functionSet = new CPPFunctionSet(candidates, templateArgs, null); return new EvalFunctionSet(functionSet, isAddressOf(expr), null, expr); + } else { + // Just store the name. ADL at the time of instantiation might come up with bindings. + return new EvalFunctionSet(name.getSimpleID(), isAddressOf(expr), expr); } } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/LookupData.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/LookupData.java index da151fec236..586e8f6e881 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/LookupData.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/LookupData.java @@ -472,12 +472,6 @@ public class LookupData extends ScopeLookupData { public void setFunctionArguments(boolean containsImpliedObject, ICPPEvaluation... exprs) { argsContainImpliedObject= containsImpliedObject; functionArgs= exprs; - for (ICPPEvaluation e : exprs) { - if (e.isTypeDependent()) { - setIgnorePointOfDeclaration(true); - break; - } - } } public void setFunctionArguments(boolean containsImpliedObject, IASTInitializerClause... exprs) { diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/index/composite/cpp/CPPCompositesFactory.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/index/composite/cpp/CPPCompositesFactory.java index df5d9d8c559..75575e0fb3b 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/index/composite/cpp/CPPCompositesFactory.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/index/composite/cpp/CPPCompositesFactory.java @@ -330,15 +330,17 @@ public class CPPCompositesFactory extends AbstractCompositeFactory { if (eval instanceof EvalFunctionSet) { EvalFunctionSet e= (EvalFunctionSet) eval; final CPPFunctionSet fset = e.getFunctionSet(); - ICPPFunction[] a = fset.getBindings(); - ICPPTemplateArgument[] b = fset.getTemplateArguments(); - IType c = e.getImpliedObjectType(); - - ICPPFunction[] a2 = getCompositeFunctionArray(a); - ICPPTemplateArgument[] b2 = TemplateInstanceUtil.convert(this, b); - IType c2 = getCompositeType(c); - if (a != a2 || b != b2 || c != c2 || templateDefinition != templateDefinition2) - e= new EvalFunctionSet(new CPPFunctionSet(a2, b2, null), e.isAddressOf(), c2, templateDefinition2); + if (fset != null) { + ICPPFunction[] a = fset.getBindings(); + ICPPTemplateArgument[] b = fset.getTemplateArguments(); + IType c = e.getImpliedObjectType(); + + ICPPFunction[] a2 = getCompositeFunctionArray(a); + ICPPTemplateArgument[] b2 = TemplateInstanceUtil.convert(this, b); + IType c2 = getCompositeType(c); + if (a != a2 || b != b2 || c != c2 || templateDefinition != templateDefinition2) + e= new EvalFunctionSet(new CPPFunctionSet(a2, b2, null), e.isAddressOf(), c2, templateDefinition2); + } return e; } if (eval instanceof EvalID) { diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/PDOM.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/PDOM.java index 25a7c72a7b2..d82538ccce7 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/PDOM.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/PDOM.java @@ -235,10 +235,11 @@ public class PDOM extends PlatformObject implements IPDOM { * 141.0 - Storing enclosing template bindings for evaluations, bug 399829. * 142.0 - Changed marshalling of evaluations to allow more than 15 evaluation kinds, bug 401479. * 143.0 - Store implied object type in EvalFunctionSet, bug 402409. + * 144.0 - Add support for storing function sets with zero functions in EvalFunctionSet, bug 402498. */ - private static final int MIN_SUPPORTED_VERSION= version(143, 0); - private static final int MAX_SUPPORTED_VERSION= version(143, Short.MAX_VALUE); - private static final int DEFAULT_VERSION = version(143, 0); + private static final int MIN_SUPPORTED_VERSION= version(144, 0); + private static final int MAX_SUPPORTED_VERSION= version(144, Short.MAX_VALUE); + private static final int DEFAULT_VERSION = version(144, 0); private static int version(int major, int minor) { return (major << 16) + minor;