On Fri, 9 Jul 2021, Patrick Palka wrote: > On Fri, 9 Jul 2021, Jason Merrill wrote: > > > On 7/9/21 3:18 PM, Patrick Palka wrote: > > > This adds support for declaring (class-scope) deduction guides for a > > > member class template. Fortunately it seems only a couple of changes > > > are needed in order for the existing CTAD machinery to handle them like > > > any other deduction guide: we need to make sure to give them a > > > FUNCTION_TYPE instead of a METHOD_TYPE, and we need to avoid using a > > > BASELINK when looking them up. > > > > > > Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for > > > trunk? > > > > > > PR c++/79501 > > > > > > gcc/cp/ChangeLog: > > > > > > * decl.c (grokfndecl): Don't require that deduction guides are > > > declared at namespace scope. Check that class-scope deduction > > > guides have the same access as the member class template. > > > (grokdeclarator): Pretend class-scope deduction guides are static. > > > * name-lookup.c (lookup_qualified_name): Don't use a BASELINK > > > for class-scope deduction guides. > > > > > > gcc/testsuite/ChangeLog: > > > > > > * g++.dg/cpp1z/class-deduction92.C: New test. > > > * g++.dg/cpp1z/class-deduction93.C: New test. > > > * g++.dg/cpp1z/class-deduction94.C: New test. > > > --- > > > gcc/cp/decl.c | 17 ++++++++----- > > > gcc/cp/name-lookup.c | 11 +++++--- > > > .../g++.dg/cpp1z/class-deduction92.C | 16 ++++++++++++ > > > .../g++.dg/cpp1z/class-deduction93.C | 25 +++++++++++++++++++ > > > .../g++.dg/cpp1z/class-deduction94.C | 19 ++++++++++++++ > > > 5 files changed, 79 insertions(+), 9 deletions(-) > > > create mode 100644 gcc/testsuite/g++.dg/cpp1z/class-deduction92.C > > > create mode 100644 gcc/testsuite/g++.dg/cpp1z/class-deduction93.C > > > create mode 100644 gcc/testsuite/g++.dg/cpp1z/class-deduction94.C > > > > > > diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c > > > index ebe1318d38d..8b8ffb7de83 100644 > > > --- a/gcc/cp/decl.c > > > +++ b/gcc/cp/decl.c > > > @@ -10040,12 +10040,6 @@ grokfndecl (tree ctype, > > > if (deduction_guide_p (decl)) > > > { > > > - if (!DECL_NAMESPACE_SCOPE_P (decl)) > > > - { > > > - error_at (location, "deduction guide %qD must be declared at " > > > - "namespace scope", decl); > > > - return NULL_TREE; > > > - } > > > > Do we still reject deduction guides at function scope? > > Yes, it looks like the parser doesn't even recognize them at function scope: > > template<class T> struct A; > > int main() { > A(int) -> A<int>; > } > > <stdin>:4:4: error: missing template arguments before ‘(’ token > <stdin>:4:5: error: expected primary-expression before ‘int’ > <stdin>:4:13: error: invalid use of ‘struct A<int>’ > > Deduction guide templates are also still rejected (as with all templates at > function scope). > > > > > > tree type = TREE_TYPE (DECL_NAME (decl)); > > > if (in_namespace == NULL_TREE > > > && CP_DECL_CONTEXT (decl) != CP_TYPE_CONTEXT (type)) > > > @@ -10055,6 +10049,13 @@ grokfndecl (tree ctype, > > > inform (location_of (type), " declared here"); > > > return NULL_TREE; > > > } > > > + if (DECL_CLASS_SCOPE_P (decl) > > > + && current_access_specifier != declared_access (TYPE_NAME (type))) > > > + { > > > + error_at (location, "deduction guide %qD must have the same access " > > > + "as %qT", decl, type); > > > + inform (location_of (type), " declared here"); > > > + } > > > if (funcdef_flag) > > > error_at (location, > > > "deduction guide %qD must not have a function body", > > > decl); > > > @@ -12035,6 +12036,10 @@ grokdeclarator (const cp_declarator *declarator, > > > storage_class = declspecs->storage_class; > > > if (storage_class == sc_static) > > > staticp = 1 + (decl_context == FIELD); > > > + else if (decl_context == FIELD && sfk == sfk_deduction_guide) > > > + /* Treat class-scope deduction guides as static member functions > > > + so that they get a FUNCTION_TYPE instead of a METHOD_TYPE. */ > > > + staticp = 2; > > > if (virtualp) > > > { > > > diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c > > > index 1be5f3da6d5..089bca1d471 100644 > > > --- a/gcc/cp/name-lookup.c > > > +++ b/gcc/cp/name-lookup.c > > > @@ -7110,9 +7110,14 @@ lookup_qualified_name (tree scope, tree name, > > > LOOK_want want, bool complain) > > > else if (cxx_dialect != cxx98 && TREE_CODE (scope) == ENUMERAL_TYPE) > > > t = lookup_enumerator (scope, name); > > > else if (is_class_type (scope, complain)) > > > - t = lookup_member (scope, name, 2, bool (want & LOOK_want::TYPE), > > > - tf_warning_or_error); > > > - > > > + { > > > + t = lookup_member (scope, name, 2, bool (want & LOOK_want::TYPE), > > > + tf_warning_or_error); > > > + if (t && dguide_name_p (name)) > > > + /* Since class-scope deduction guides aren't really member functions, > > > + don't use a BASELINK for them. */ > > > + t = MAYBE_BASELINK_FUNCTIONS (t); > > > + }
On second thought, this seems to be an awkward spot to do this adjustment. Maybe it's better to do it in lookup_member, or in deduction_guides_for (the only caller which really needs it)? > > > if (!t) > > > return error_mark_node; > > > return t; > > > diff --git a/gcc/testsuite/g++.dg/cpp1z/class-deduction92.C > > > b/gcc/testsuite/g++.dg/cpp1z/class-deduction92.C > > > new file mode 100644 > > > index 00000000000..178234c76d1 > > > --- /dev/null > > > +++ b/gcc/testsuite/g++.dg/cpp1z/class-deduction92.C > > > @@ -0,0 +1,16 @@ > > > +// PR c++/79501 > > > +// { dg-do compile { target c++17 } } > > > + > > > +template<auto V> > > > +struct X { > > > + template<class T> > > > + struct B { T t; }; > > > + > > > + template<class T> B(T) -> B<const T>; > > > + > > > + auto foo() { return B{V}; } > > > +}; > > > + > > > +X<42> x; > > > +using type = decltype(x.foo()); > > > +using type = X<42>::B<const int>; > > > diff --git a/gcc/testsuite/g++.dg/cpp1z/class-deduction93.C > > > b/gcc/testsuite/g++.dg/cpp1z/class-deduction93.C > > > new file mode 100644 > > > index 00000000000..9d2db7a55a2 > > > --- /dev/null > > > +++ b/gcc/testsuite/g++.dg/cpp1z/class-deduction93.C > > > @@ -0,0 +1,25 @@ > > > +// PR c++/79501 > > > +// { dg-do compile { target c++17 } } > > > +// A variant of class-deduction78.C where List and its deduction guides > > > are > > > +// defined at class scope. > > > + > > > +using size_t = decltype(sizeof(42)); > > > + > > > +struct A { > > > + template<typename T, size_t N = 0> > > > + struct List { > > > + T head; > > > + List<T, N-1> tail; > > > + }; > > > + > > > + template<typename T> > > > + struct List<T, 0> {}; > > > + > > > + template<typename T> List(T) -> List<T, 1>; > > > + template<typename T, size_t N> List(T, List<T, N>) -> List<T, N+1>; > > > +}; > > > + > > > +int main() { > > > + using type = decltype(A::List{0, A::List{1, A::List{2}}}); > > > + using type = A::List<int, 3>; > > > +} > > > diff --git a/gcc/testsuite/g++.dg/cpp1z/class-deduction94.C > > > b/gcc/testsuite/g++.dg/cpp1z/class-deduction94.C > > > new file mode 100644 > > > index 00000000000..f29ebd2c2b8 > > > --- /dev/null > > > +++ b/gcc/testsuite/g++.dg/cpp1z/class-deduction94.C > > > @@ -0,0 +1,19 @@ > > > +// PR c++/79501 > > > +// { dg-do compile { target c++17 } } > > > + > > > +struct X { > > > +protected: > > > + template<class T> > > > + struct B { T t; }; > > > + > > > + template<class T> B(T) -> B<T>; > > > +}; > > > + > > > +struct Y { > > > +protected: > > > + template<class T> > > > + struct B { T t; }; > > > + > > > +private: > > > + template<class T> B(T) -> B<T>; // { dg-error "access" } > > > +}; > > > > > > >