TemplateDeductionInfo &Info,
SmallVectorImpl<DeducedTemplateArgument> &Deduced,
unsigned TDF, Sema::TemplateDeductionResult &Result) {
- // If the argument is an initializer list then the parameter is an undeduced
- // context, unless the parameter type is (reference to cv)
- // std::initializer_list<P'>, in which case deduction is done for each element
- // of the initializer list as-if it were an argument in a function call, and
- // the result is the deduced type if it's the same for all elements.
- QualType X;
- if (!S.isStdInitializerList(AdjustedParamType, &X))
+
+ // [temp.deduct.call] p1 (post CWG-1591)
+ // If removing references and cv-qualifiers from P gives
+ // std::initializer_list<P0> or P0[N] for some P0 and N and the argument is a
+ // non-empty initializer list (8.5.4), then deduction is performed instead for
+ // each element of the initializer list, taking P0 as a function template
+ // parameter type and the initializer element as its argument, and in the
+ // P0[N] case, if N is a non-type template parameter, N is deduced from the
+ // length of the initializer list. Otherwise, an initializer list argument
+ // causes the parameter to be considered a non-deduced context
+
+ const bool IsConstSizedArray = AdjustedParamType->isConstantArrayType();
+
+ const bool IsDependentSizedArray =
+ !IsConstSizedArray && AdjustedParamType->isDependentSizedArrayType();
+
+ QualType ElTy; // The type of the std::initializer_list or the array element.
+
+ const bool IsSTDList = !IsConstSizedArray && !IsDependentSizedArray &&
+ S.isStdInitializerList(AdjustedParamType, &ElTy);
+
+ if (!IsConstSizedArray && !IsDependentSizedArray && !IsSTDList)
return false;
Result = Sema::TDK_Success;
-
- // Recurse down into the init list.
- for (unsigned i = 0, e = ILE->getNumInits(); i < e; ++i) {
- if ((Result = DeduceTemplateArgumentByListElement(
- S, TemplateParams, X, ILE->getInit(i), Info, Deduced, TDF)))
- return true;
+ // If we are not deducing against the 'T' in a std::initializer_list<T> then
+ // deduce against the 'T' in T[N].
+ if (ElTy.isNull()) {
+ assert(!IsSTDList);
+ ElTy = S.Context.getAsArrayType(AdjustedParamType)->getElementType();
+ }
+ // Deduction only needs to be done for dependent types.
+ if (ElTy->isDependentType()) {
+ for (Expr *E : ILE->inits()) {
+ if (Result = DeduceTemplateArgumentByListElement(S, TemplateParams, ElTy,
+ E, Info, Deduced, TDF))
+ return true;
+ }
}
+ if (IsDependentSizedArray) {
+ const DependentSizedArrayType *ArrTy =
+ S.Context.getAsDependentSizedArrayType(AdjustedParamType);
+ // Determine the array bound is something we can deduce.
+ if (NonTypeTemplateParmDecl *NTTP =
+ getDeducedParameterFromExpr(ArrTy->getSizeExpr())) {
+ // We can perform template argument deduction for the given non-type
+ // template parameter.
+ assert(NTTP->getDepth() == 0 &&
+ "Cannot deduce non-type template argument at depth > 0");
+ llvm::APInt Size(S.Context.getIntWidth(NTTP->getType()),
+ ILE->getNumInits());
+ Result = DeduceNonTypeTemplateArgument(
+ S, NTTP, llvm::APSInt(Size), NTTP->getType(),
+ /*ArrayBound=*/true, Info, Deduced);
+ }
+ }
return true;
}
}
} // dr1589
+
+namespace dr1591 { //dr1591. Deducing array bound and element type from initializer list
+ template<class T, int N> int h(T const(&)[N]);
+ int X = h({1,2,3}); // T deduced to int, N deduced to 3
+
+ template<class T> int j(T const(&)[3]);
+ int Y = j({42}); // T deduced to int, array bound not considered
+
+ struct Aggr { int i; int j; };
+ template<int N> int k(Aggr const(&)[N]); //expected-note{{not viable}}
+ int Y0 = k({1,2,3}); //expected-error{{no matching function}}
+ int Z = k({{1},{2},{3}}); // OK, N deduced to 3
+
+ template<int M, int N> int m(int const(&)[M][N]);
+ int X0 = m({{1,2},{3,4}}); // M and N both deduced to 2
+
+ template<class T, int N> int n(T const(&)[N], T);
+ int X1 = n({{1},{2},{3}},Aggr()); // OK, T is Aggr, N is 3
+
+
+ namespace check_multi_dim_arrays {
+ template<class T, int N, int M, int O> int ***f(const T (&a)[N][M][O]); //expected-note{{deduced conflicting values}}
+ template<class T, int N, int M> int **f(const T (&a)[N][M]); //expected-note{{couldn't infer}}
+
+ template<class T, int N> int *f(const T (&a)[N]); //expected-note{{couldn't infer}}
+ int ***p3 = f({ { {1,2}, {3, 4} }, { {5,6}, {7, 8} }, { {9,10}, {11, 12} } });
+ int ***p33 = f({ { {1,2}, {3, 4} }, { {5,6}, {7, 8} }, { {9,10}, {11, 12, 13} } }); //expected-error{{no matching}}
+ int **p2 = f({ {1,2,3}, {3, 4, 5} });
+ int **p22 = f({ {1,2}, {3, 4} });
+ int *p1 = f({1, 2, 3});
+ }
+ namespace check_multi_dim_arrays_rref {
+ template<class T, int N, int M, int O> int ***f(T (&&a)[N][M][O]); //expected-note{{deduced conflicting values}}
+ template<class T, int N, int M> int **f(T (&&a)[N][M]); //expected-note{{couldn't infer}}
+
+ template<class T, int N> int *f(T (&&a)[N]); //expected-note{{couldn't infer}}
+ int ***p3 = f({ { {1,2}, {3, 4} }, { {5,6}, {7, 8} }, { {9,10}, {11, 12} } });
+ int ***p33 = f({ { {1,2}, {3, 4} }, { {5,6}, {7, 8} }, { {9,10}, {11, 12, 13} } }); //expected-error{{no matching}}
+ int **p2 = f({ {1,2,3}, {3, 4, 5} });
+ int **p22 = f({ {1,2}, {3, 4} });
+ int *p1 = f({1, 2, 3});
+ }
+
+ namespace check_arrays_of_init_list {
+ template<class T, int N> float *f(const std::initializer_list<T> (&)[N]);
+ template<class T, int N> double *f(const T(&)[N]);
+ double *p = f({1, 2, 3});
+ float *fp = f({{1}, {1, 2}, {1, 2, 3}});
+ }
+} // dr1591
+
#endif