diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2CPPTests.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2CPPTests.java index 4efad870798..1d14273bbe6 100644 --- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2CPPTests.java +++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2CPPTests.java @@ -8899,6 +8899,34 @@ public class AST2CPPTests extends AST2TestBase { parseAndCheckBindings(); } + // struct A { + // A(); + // A(int); + // A(int, int); + // }; + // + // void test() { + // A{}; + // A{1}; + // A{1, 2}; + // } + public void testListInitializer_495227() throws Exception { + parseAndCheckBindings(); + BindingAssertionHelper ah = getAssertionHelper(); + IASTImplicitName name = ah.findImplicitName("A{}", 1); + IBinding binding = name.resolveBinding(); + assertTrue(binding instanceof ICPPConstructor); + assertEquals(0, ((ICPPConstructor) binding).getType().getParameterTypes().length); + name = ah.findImplicitName("A{1}", 1); + binding = name.resolveBinding(); + assertTrue(binding instanceof ICPPConstructor); + assertEquals(1, ((ICPPConstructor) binding).getType().getParameterTypes().length); + name = ah.findImplicitName("A{1, 2}", 1); + binding = name.resolveBinding(); + assertTrue(binding instanceof ICPPConstructor); + assertEquals(2, ((ICPPConstructor) binding).getType().getParameterTypes().length); + } + // namespace std { // template class initializer_list; // } 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 317c84a4494..16ee6d7372a 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 @@ -9436,7 +9436,7 @@ public class AST2TemplateTests extends AST2TestBase { public void testRecursiveTemplateClass_484786() throws Exception { parseAndCheckBindings(); } - + // template // struct S { // static const bool value = true; @@ -9448,4 +9448,30 @@ public class AST2TemplateTests extends AST2TestBase { public void testDisambiguationInNoexceptSpecifier_467332() throws Exception { parseAndCheckBindings(); } + + // template + // struct is_same {}; + // + // template + // struct is_same { + // constexpr operator bool() { return true; } + // }; + // + // template + // struct enable_if {}; + // + // template<> + // struct enable_if { + // typedef void type; + // }; + // + // template + // typename enable_if{}>::type waldo(T p); + // + // void test() { + // waldo(1); + // } + public void testListInitialization_495091() throws Exception { + parseAndCheckBindings(); + } } 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 889c9101972..d68659e6b54 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 @@ -2730,9 +2730,15 @@ public class CPPTemplates { } return null; } - Cost cost = Conversions.checkImplicitConversionSequence(p, a, LVALUE, UDCMode.FORBIDDEN, Context.ORDINARY, point); - if (cost == null || !cost.converts()) - return null; + Cost cost = Conversions.checkImplicitConversionSequence(p, a, LVALUE, UDCMode.FORBIDDEN, + Context.ORDINARY, point); + if (cost == null || !cost.converts()) { + ICPPEvaluation eval = arg.getNonTypeEvaluation(); + ICPPEvaluation newEval = CPPEvaluation.maybeApplyConversion(eval, p, point); + if (newEval == EvalFixed.INCOMPLETE && newEval != eval) + return null; + return new CPPTemplateNonTypeArgument(newEval, point); + } return new CPPTemplateNonTypeArgument(arg.getNonTypeValue(), paramType); } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalFixed.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalFixed.java index 726e304d3c1..2dae9b53196 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalFixed.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/EvalFixed.java @@ -19,6 +19,7 @@ import org.eclipse.cdt.core.dom.ast.IASTExpression.ValueCategory; import org.eclipse.cdt.core.dom.ast.IASTNode; import org.eclipse.cdt.core.dom.ast.IType; import org.eclipse.cdt.core.dom.ast.IValue; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassType; import org.eclipse.cdt.core.dom.ast.cpp.ICPPParameterPackType; import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateParameterMap; import org.eclipse.cdt.internal.core.dom.parser.ISerializableEvaluation; @@ -109,7 +110,8 @@ public class EvalFixed extends CPPEvaluation { @Override public boolean isConstantExpression(IASTNode point) { - return isConstexprValue(fValue, point); + return (fType instanceof ICPPClassType && TypeTraits.isEmpty(fType, point)) + || isConstexprValue(fValue, point); } @Override 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 11e093d9e5e..9f1eaa46366 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 @@ -22,16 +22,21 @@ import org.eclipse.cdt.core.dom.ast.IBinding; import org.eclipse.cdt.core.dom.ast.IProblemBinding; import org.eclipse.cdt.core.dom.ast.IType; import org.eclipse.cdt.core.dom.ast.IValue; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassTemplate; import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassType; import org.eclipse.cdt.core.dom.ast.cpp.ICPPConstructor; import org.eclipse.cdt.core.dom.ast.cpp.ICPPFunction; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPMethod; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPSpecialization; 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; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPFunction; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPPointerType; import org.eclipse.cdt.internal.core.dom.parser.cpp.ClassTypeHelper; +import org.eclipse.cdt.internal.core.dom.parser.cpp.ClassTypeHelper.MethodKind; import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPEvaluation; import org.eclipse.cdt.internal.core.dom.parser.cpp.InstantiationContext; import org.eclipse.core.runtime.CoreException; @@ -170,10 +175,30 @@ public class EvalTypeId extends CPPDependentEvaluation { IType simplifiedType = SemanticUtil.getNestedType(fInputType, SemanticUtil.TDEF); if (simplifiedType instanceof ICPPClassType) { ICPPClassType classType = (ICPPClassType) simplifiedType; - LookupData data = new LookupData(classType.getNameCharArray(), null, point); + ICPPEvaluation[] arguments = fArguments; ICPPConstructor[] constructors = ClassTypeHelper.getConstructors(classType, point); + if (arguments.length == 1 && arguments[0] instanceof EvalInitList) { + // List-initialization of a class (dcl.init.list-3). + if (TypeTraits.isAggregateClass(classType, point)) { + // Pretend that aggregate initialization is calling the default constructor. + return findDefaultConstructor(classType, constructors); + } + if (((EvalInitList) arguments[0]).getClauses().length == 0) { + ICPPMethod ctor = findDefaultConstructor(classType, constructors); + if (ctor != null) + return ctor; + } + ICPPConstructor[] ctors = getInitializerListConstructors(constructors, point); + if (ctors.length != 0) { + constructors = ctors; + } else { + arguments = ((EvalInitList) arguments[0]).getClauses(); + } + } + + LookupData data = new LookupData(classType.getNameCharArray(), null, point); data.foundItems = constructors; - data.setFunctionArguments(false, fArguments); + data.setFunctionArguments(false, arguments); try { IBinding binding = CPPSemantics.resolveFunction(data, constructors, true); if (binding instanceof ICPPFunction) { @@ -186,6 +211,39 @@ public class EvalTypeId extends CPPDependentEvaluation { return null; } + private ICPPConstructor findDefaultConstructor(ICPPClassType classType, ICPPConstructor[] constructors) { + for (ICPPConstructor ctor : constructors) { + if (ctor.isImplicit() && ClassTypeHelper.getMethodKind(classType, ctor) == MethodKind.DEFAULT_CTOR) + return ctor; + } + return null; + } + + /** + * Returns constructors that can be called by passing a single {@code std::initializer_list} + * as an argument. + */ + private ICPPConstructor[] getInitializerListConstructors(ICPPConstructor[] constructors, IASTNode point) { + ICPPConstructor[] result = ICPPConstructor.EMPTY_CONSTRUCTOR_ARRAY; + ICPPClassTemplate template = CPPVisitor.get_initializer_list(point); + for (ICPPConstructor ctor : constructors) { + if (ctor.getRequiredArgumentCount() <= 1) { + IType[] parameterTypes = ctor.getType().getParameterTypes(); + if (parameterTypes.length != 0) { + IType type = parameterTypes[0]; + if (type instanceof ICPPSpecialization) { + IBinding specialized = ((ICPPSpecialization) type).getSpecializedBinding(); + if (specialized instanceof ICPPClassTemplate + && template.isSameType((IType) specialized)) { + result = ArrayUtil.append(result, ctor); + } + } + } + } + } + return ArrayUtil.trim(result); + } + @Override public void marshal(ITypeMarshalBuffer buffer, boolean includeValue) throws CoreException { short firstBytes = ITypeMarshalBuffer.EVAL_TYPE_ID;