Hi Jason, I've addressed your review comments and provided support for conversion to function pointer for generic lambdas. I've sent the patches as updates to the previous set. I'll wait for any further comments before formalizing them into a cleaner set.
The changes now support the examples given in N3690 ยง5.1.2.{5,6} and the test program included at the end of this mail. I think it is feature-complete. On 19.07.2013 17:56, Jason Merrill wrote: > On 07/19/2013 05:00 AM, Adam Butcher wrote: > > > > + push_deferring_access_checks (dk_deferred); > > > Why do you need this? > I don't think I do. I had thought that it would be necessary to handle deferred friendship situations but I don't think that can apply to generic lambdas. I've ditched them. > > +/* Nonzero if the function being declared was made a template due to it's > > > "its" > I've fixed this and a couple of others in my own comments. I've also fixed others I found in the same file (as a separate patch). > > + else // extend current template parameter list > > > Do we still need to do this, now that we're handling all the > parameters at the end of the parameter list? > I think extending the current parameter list is still needed when 'auto' is found in a parameter declaration of an existing function template. E.g. template <typename T> void f(T& t, auto& a) { ... } I think that it is necessary to keep everything consistent as if the template had been declared in the 'conventional' way. The template parameter generated for the generic parameter 'a' effectively makes 'f's template parameter list into '<typename T, typename __Gen0>'. Cheers, Adam Patch summary (4): Preserve type qualifiers for implicit template parameters. Support implicit conversion of a stateless generic lambda to a function pointer. Address review comments. Grammar "it's" to "its". gcc/cp/cp-tree.h | 2 +- gcc/cp/decl.c | 3 ++- gcc/cp/lambda.c | 77 +++++++++++++++++++++++++++++++++++++++++--------------- gcc/cp/parser.c | 6 ++--- gcc/cp/pt.c | 21 ++++++++++------ 5 files changed, 76 insertions(+), 33 deletions(-) Test program: /* Function templates at namespace scope. */ auto f1 (auto& a, auto const& b) { return a += b; } template <typename A> auto f2 (A& a, auto const& b) { return a += b; } template <typename B> auto f3 (auto& a, B const& b) { return a += b; } template <typename A, typename B> auto f4 (A& a, B const& b) { return a += b; } struct S { /* Non-static member function templates. */ auto mf1 (auto& a, auto const& b) { return a += b; } template <typename A> auto mf2 (A& a, auto const& b) { return a += b; } template <typename B> auto mf3 (auto& a, B const& b) { return a += b; } template <typename A, typename B> auto mf4 (A& a, B const& b) { return a += b; } /* Static member function templates. */ static auto smf1 (auto& a, auto const& b) { return a += b; } template <typename A> static auto smf2 (A& a, auto const& b) { return a += b; } template <typename B> static auto smf3 (auto& a, B const& b) { return a += b; } template <typename A, typename B> static auto smf4 (A& a, B const& b) { return a += b; } }; #undef NDEBUG #include <cassert> #define CHECK(A, b, f) do { \ A a1 = 5, a2 = 12; \ auto r1 = f (a1, b); \ auto r2 = f (a2, b); \ assert ((#f, a1 == 5 + b)); \ assert ((#f, a2 == 12 + b)); \ assert ((#f, r1 == a1)); \ assert ((#f, r2 == a2)); \ } while (0) #define INVOKEi(f, A, b, i) do { CHECK (A, b, f ## i); } while (0) #define INVOKE4(f, A, b) do { INVOKEi (f, A, b, 1); \ INVOKEi (f, A, b, 2); \ INVOKEi (f, A, b, 3); \ INVOKEi (f, A, b, 4); } while (0) #define AS_FUNi(f, A, b, i) do { CHECK (A, b, f ## i._FUN); } while (0) #define AS_FUN4(f, A, b) do { AS_FUNi (f, A, b, 1); \ AS_FUNi (f, A, b, 2); \ AS_FUNi (f, A, b, 3); \ AS_FUNi (f, A, b, 4); } while (0) #define AS_PTRi(f, A, B, b, i) do { A (*pfn) (A&, B const&) = f ## i; \ CHECK (A, b, pfn); } while (0) #define AS_PTR4(f, A, B, b) do { AS_PTRi (f, A, B, b, 1); \ AS_PTRi (f, A, B, b, 2); \ AS_PTRi (f, A, B, b, 3); \ AS_PTRi (f, A, B, b, 4); } while (0) int main() { /* Check namespace templates. */ INVOKE4 (f, float, 7); AS_PTR4 (f, float, int, 7); /* Check member templates. */ S s; INVOKE4 (s.mf, float, 7); INVOKE4 (s.smf, float, 7); INVOKE4 (S::smf, float, 7); AS_PTR4 (s.smf, float, int, 7); AS_PTR4 (S::smf, float, int, 7); /* Regression check non-template stateless lambda and its conversion to function pointer. */ auto lf0 = [] (float& a, int const& b) { return a += b; }; INVOKEi (lf, float, 7, 0); AS_FUNi (lf, float, 7, 0); AS_PTRi (lf, float, int, 7, 0); /* Check stateless lambda templates. */ auto lf1 = [] (auto& a, auto const& b) { return a += b; }; auto lf2 = [] <typename A> (A& a, auto const& b) { return a += b; }; auto lf3 = [] <typename B> (auto& a, B const& b) { return a += b; }; auto lf4 = [] <typename A, typename B> (A& a, B const& b) { return a += b; }; INVOKE4 (lf, float, 7); AS_FUN4 (lf, float, 7); AS_PTR4 (lf, float, int, 7); /* Check capturing lambda templates. */ int i; auto lc1 = [i] (auto& a, auto const& b) { return a += b; }; auto lc2 = [i] <typename A> (A& a, auto const& b) { return a += b; }; auto lc3 = [i] <typename B> (auto& a, B const& b) { return a += b; }; auto lc4 = [i] <typename A, typename B> (A& a, B const& b) { return a += b; }; INVOKE4 (lc, float, 7); } -- 1.8.3