From 2734b7ae8295dd4dde0d4383b2bcf7dc708a072a Mon Sep 17 00:00:00 2001 From: Davin McCall Date: Sun, 19 May 2019 20:02:34 +1000 Subject: [PATCH] Bug 545040 - make array size inference work with initializer lists Resolution for DR1591 clarified that initializer list size could be used to deduce array size (if it is a template parameter). Change-Id: Ic3617e31b125083f1205f91383eb27f5e5a29041 Signed-off-by: Davin McCall --- .../parser/tests/ast2/AST2TemplateTests.java | 57 ++++++++++++++++ .../semantics/TemplateArgumentDeduction.java | 65 +++++++++++++------ 2 files changed, 102 insertions(+), 20 deletions(-) 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 c53ccaa951c..c42ac4dd8cd 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 @@ -425,6 +425,63 @@ public class AST2TemplateTests extends AST2CPPTestBase { assertEquals(f.getID(), IProblemBinding.SEMANTIC_AMBIGUOUS_LOOKUP); } + // template < int N > void f(const int (&v)[N]); + // void main() { + // f({1,2,3}); + // } + public void test_dr1591_DeduceArrayFromInitializerList_a() throws Exception { + IASTTranslationUnit tu = parse(getAboveComment(), CPP); + NameCollector col = new NameCollector(); + tu.accept(col); + + ICPPFunctionTemplate f = (ICPPFunctionTemplate) col.getName(1).resolveBinding(); + assertEquals("f", col.getName(5).toString()); + + IBinding fCall = col.getName(5).resolveBinding(); + assertInstance(fCall, IFunction.class); + IFunction f2 = (IFunction) fCall; + assertInstance(f2, ICPPTemplateInstance.class); + assertSame(f, ((ICPPTemplateInstance) f2).getTemplateDefinition()); + } + + // template < typename T, int N > void f(const T (&v)[N]); + // void main() { + // f({1,2,3}); + // } + public void test_dr1591_DeduceArrayFromInitializerList_b() throws Exception { + IASTTranslationUnit tu = parse(getAboveComment(), CPP); + NameCollector col = new NameCollector(); + tu.accept(col); + + ICPPFunctionTemplate f = (ICPPFunctionTemplate) col.getName(2).resolveBinding(); + assertEquals("f", col.getName(7).toString()); + + IBinding fCall = col.getName(7).resolveBinding(); + assertInstance(fCall, IFunction.class); + IFunction f2 = (IFunction) fCall; + assertInstance(f2, ICPPTemplateInstance.class); + assertSame(f, ((ICPPTemplateInstance) f2).getTemplateDefinition()); + } + + // template < typename T, int N > void f(const T (&v)[N]); + // void main() { + // f({1,2.0,3}); + // } + public void test_dr1591_DeduceArrayFromInitializerList_c() throws Exception { + IASTTranslationUnit tu = parse(getAboveComment(), CPP); + NameCollector col = new NameCollector(); + tu.accept(col); + + ICPPFunctionTemplate f = (ICPPFunctionTemplate) col.getName(2).resolveBinding(); + assertEquals("f", col.getName(7).toString()); + + IBinding fCall = col.getName(7).resolveBinding(); + assertInstance(fCall, IProblemBinding.class); + + IProblemBinding fCallPB = (IProblemBinding) fCall; + assertEquals(IProblemBinding.SEMANTIC_NAME_NOT_FOUND, fCallPB.getID()); + } + // template < class T, template < class X > class U, T *pT > class A { // }; public void testTemplateParameters() throws Exception { diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/TemplateArgumentDeduction.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/TemplateArgumentDeduction.java index 9cf6aee19ac..1ceb1694fc9 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/TemplateArgumentDeduction.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/TemplateArgumentDeduction.java @@ -148,7 +148,20 @@ public class TemplateArgumentDeduction { par = SemanticUtil.getNestedType(par, TDEF | REF | CVTYPE); // Check if this is a deduced context. - IType inner = Conversions.getInitListType(par); + IType inner = null; + if (par instanceof IArrayType) { + // As per DR1591, if an initializer list is given as an argument for parameter type P[N], + // we can deduce N from the size of the initializer list (and potentially deduce P from + // the elements in the list). + inner = ((IArrayType) par).getType(); + IValue as = IntegralValue + .create(((InitializerListType) arg).getEvaluation().getClauses().length); + IValue ps = ((IArrayType) par).getSize(); + if (!deduct.fromArraySize(ps, as)) + return false; + } else { + inner = Conversions.getInitListType(par); + } if (inner != null) { final EvalInitList eval = ((InitializerListType) arg).getEvaluation(); for (ICPPEvaluation clause : eval.getClauses()) { @@ -853,6 +866,35 @@ public class TemplateArgumentDeduction { && fromType(p.getTypeValue(), a.getTypeValue(), false, true)); } + /** + * Deduce a parameter array size from an argument array size. + * @param ps the parameter size (may refer to template parameter) + * @param as the argument array or initializer list size + * @return false if deduction encountered an error, true otherwise + */ + private boolean fromArraySize(IValue ps, IValue as) { + if (as != ps) { + if (as == null || ps == null) + return false; + + int parID = IntegralValue.isTemplateParameter(ps); + if (parID >= 0) { + ICPPTemplateArgument old = fDeducedArgs.getArgument(parID, fPackOffset); + if (old == null) { + if (!deduce(parID, new CPPTemplateNonTypeArgument(as, new TypeOfValueDeducedFromArraySize()))) { + return false; + } + } else if (!as.equals(old.getNonTypeValue())) { + return false; + } + } else if (!as.equals(ps)) { + return false; + } + } + + return true; + } + private boolean fromType(IType p, IType a, boolean allowCVQConversion, boolean verifyNonDeduced) throws DOMException { IType originalArgType = a; @@ -910,25 +952,8 @@ public class TemplateArgumentDeduction { IArrayType pa = (IArrayType) p; IValue as = aa.getSize(); IValue ps = pa.getSize(); - if (as != ps) { - if (as == null || ps == null) - return false; - - int parID = IntegralValue.isTemplateParameter(ps); - if (parID >= 0) { - ICPPTemplateArgument old = fDeducedArgs.getArgument(parID, fPackOffset); - if (old == null) { - if (!deduce(parID, - new CPPTemplateNonTypeArgument(as, new TypeOfValueDeducedFromArraySize()))) { - return false; - } - } else if (!as.equals(old.getNonTypeValue())) { - return false; - } - } else if (!as.equals(as)) { - return false; - } - } + if (!fromArraySize(ps, as)) + return false; p = pa.getType(); a = aa.getType(); } else if (p instanceof IQualifierType) {