Skip to content

Commit f2e794e

Browse files
committed
Support arrays
1 parent 8124374 commit f2e794e

2 files changed

Lines changed: 61 additions & 0 deletions

File tree

‎lib/templatesimplifier.cpp‎

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -863,6 +863,33 @@ static ParameterShape parseParameterShape(const Token* start, const std::vector<
863863
return shape;
864864
}
865865

866+
// Whether the argument expression has an array type that the deduction would get wrong:
867+
// the ValueType of an array has its dimensions as pointer levels. With array to pointer
868+
// decay (a "T" or "T *" parameter) only the outermost dimension becomes a pointer, so a
869+
// multidimensional array is not deducible; without decay (a "T &" parameter) no array is.
870+
// consumed is the number of dimensions that enclosing "[" and "*" operators strip off.
871+
static bool isUndecayedArray(const Token* tok, bool decay, std::size_t consumed = 0)
872+
{
873+
if (!tok)
874+
return false;
875+
if (tok->variable()) {
876+
const std::size_t dimensions = tok->variable()->dimensions().size();
877+
if (dimensions <= consumed)
878+
return false;
879+
return !decay || dimensions - consumed >= 2;
880+
}
881+
if (tok->str() == "[" || tok->isUnaryOp("*"))
882+
return isUndecayedArray(tok->astOperand1(), decay, consumed + 1);
883+
if (tok->isUnaryOp("&")) // the address of an array is a pointer to the array - no decay
884+
return isUndecayedArray(tok->astOperand1(), false, consumed);
885+
if (Token::Match(tok, ".|::|?"))
886+
return isUndecayedArray(tok->astOperand2(), decay, consumed);
887+
if (tok->str() == ":")
888+
return isUndecayedArray(tok->astOperand1(), decay, consumed) ||
889+
isUndecayedArray(tok->astOperand2(), decay, consumed);
890+
return false;
891+
}
892+
866893
// Complete a deduced type with the qualified name of a record or enum scope. The
867894
// returned type has an empty typeStr when the scope cannot be named.
868895
static DeducedType deducedScopeType(DeducedType deduced, const Scope* typeScope)
@@ -1353,6 +1380,8 @@ std::string TemplateSimplifier::deduceFunctionTemplateArguments(
13531380
mPendingTypeDeductions = true;
13541381
return qualification;
13551382
}
1383+
if (vt->pointer > 0 && isUndecayedArray(argRoots[i], !shape.isReference))
1384+
return qualification;
13561385
DeducedType deduced = valueTypeToDeducedType(vt, shape);
13571386
if (deduced.typeStr.empty())
13581387
return qualification;

‎test/testsimplifytemplate.cpp‎

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -316,6 +316,7 @@ class TestSimplifyTemplate : public TestFixture {
316316
TEST_CASE(templateTypeDeductionFullRebuild); // --template-full-rebuild gives the same result
317317
TEST_CASE(templateTypeDeductionMultiPass); // a pending deduction survives later simplifier passes
318318
TEST_CASE(templateTypeDeductionEnum); // enum arguments deduce the enum, not its underlying type
319+
TEST_CASE(templateTypeDeductionArray); // array arguments: only the decayed dimension is a pointer
319320

320321
TEST_CASE(simplifyTemplateArgs1);
321322
TEST_CASE(simplifyTemplateArgs2);
@@ -7344,6 +7345,37 @@ class TestSimplifyTemplate : public TestFixture {
73447345
}
73457346
}
73467347

7348+
void templateTypeDeductionArray()
7349+
{ // the ValueType of an array has the dimensions as pointer levels. A reference
7350+
// parameter binds the array itself (T = int[3]) and a multidimensional array decays
7351+
// only its outermost dimension - neither is a pointer type, so bail out
7352+
const char code[] = "template<class T> void f(T& x) {}\n"
7353+
"template<class T> void g(const T& x) {}\n"
7354+
"template<class T> void h(T* x) {}\n"
7355+
"template<class T> void k(T x) {}\n"
7356+
"struct S { int m[2]; };\n"
7357+
"void test(S s, S* p, bool c) {\n"
7358+
" int a[3]; int b[2][3]; int* q[2]; int i;\n"
7359+
" f(a); g(a); f(b); h(b); k(b); f(s.m); f(p->m); f(&a); f(q); f(*b); g(c ? a : a);\n"
7360+
" f(i); h(a); k(a); f(a[0]); h(b[0]); k(q); h(&a[0]); k(&i);\n"
7361+
"}";
7362+
const char exp[] = "void f<int> ( int & x ) ; "
7363+
"template < class T > void g ( const T & x ) { } "
7364+
"void h<int> ( int * x ) ; "
7365+
"void k<int*> ( int * x ) ; void k<int**> ( int * * x ) ; "
7366+
"struct S { int m [ 2 ] ; } ; "
7367+
"void test ( S s , S * p , bool c ) { "
7368+
"int a [ 3 ] ; int b [ 2 ] [ 3 ] ; int * q [ 2 ] ; int i ; "
7369+
"f ( a ) ; g ( a ) ; f ( b ) ; h ( b ) ; k ( b ) ; f ( s . m ) ; f ( p . m ) ; f ( & a ) ; f ( q ) ; f ( * b ) ; g ( c ? a : a ) ; "
7370+
"f<int> ( i ) ; h<int> ( a ) ; k<int*> ( a ) ; f<int> ( a [ 0 ] ) ; h<int> ( b [ 0 ] ) ; k<int**> ( q ) ; h<int> ( & a [ 0 ] ) ; k<int*> ( & i ) ; "
7371+
"} "
7372+
"void k<int*> ( int * x ) { } void k<int**> ( int * * x ) { } "
7373+
"void h<int> ( int * x ) { } "
7374+
"void f<int> ( int & x ) { }";
7375+
ASSERT_EQUALS(exp, tok(code));
7376+
ASSERT_EQUALS("", errout_str());
7377+
}
7378+
73477379
void simplifyTemplateArgs1() {
73487380
ASSERT_EQUALS("foo<2> = 2 ; foo<2> ;", tok("template<int N> foo = N; foo < ( 2 ) >;\n"));
73497381
ASSERT_EQUALS("foo<2> = 2 ; foo<2> ;", tok("template<int N> foo = N; foo < 1 + 1 >;\n"));

0 commit comments

Comments
 (0)