1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-08-15 04:05:38 +02:00

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 <davmac@davmac.org>
This commit is contained in:
Davin McCall 2019-05-19 20:02:34 +10:00 committed by Nathan Ridge
parent 1cd0e1df35
commit 2734b7ae82
2 changed files with 102 additions and 20 deletions

View file

@ -425,6 +425,63 @@ public class AST2TemplateTests extends AST2CPPTestBase {
assertEquals(f.getID(), IProblemBinding.SEMANTIC_AMBIGUOUS_LOOKUP); 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 { // template < class T, template < class X > class U, T *pT > class A {
// }; // };
public void testTemplateParameters() throws Exception { public void testTemplateParameters() throws Exception {

View file

@ -148,7 +148,20 @@ public class TemplateArgumentDeduction {
par = SemanticUtil.getNestedType(par, TDEF | REF | CVTYPE); par = SemanticUtil.getNestedType(par, TDEF | REF | CVTYPE);
// Check if this is a deduced context. // 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) { if (inner != null) {
final EvalInitList eval = ((InitializerListType) arg).getEvaluation(); final EvalInitList eval = ((InitializerListType) arg).getEvaluation();
for (ICPPEvaluation clause : eval.getClauses()) { for (ICPPEvaluation clause : eval.getClauses()) {
@ -853,6 +866,35 @@ public class TemplateArgumentDeduction {
&& fromType(p.getTypeValue(), a.getTypeValue(), false, true)); && 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) private boolean fromType(IType p, IType a, boolean allowCVQConversion, boolean verifyNonDeduced)
throws DOMException { throws DOMException {
IType originalArgType = a; IType originalArgType = a;
@ -910,25 +952,8 @@ public class TemplateArgumentDeduction {
IArrayType pa = (IArrayType) p; IArrayType pa = (IArrayType) p;
IValue as = aa.getSize(); IValue as = aa.getSize();
IValue ps = pa.getSize(); IValue ps = pa.getSize();
if (as != ps) { if (!fromArraySize(ps, as))
if (as == null || ps == null) return false;
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;
}
}
p = pa.getType(); p = pa.getType();
a = aa.getType(); a = aa.getType();
} else if (p instanceof IQualifierType) { } else if (p instanceof IQualifierType) {