On Thu, 25 Feb 2021, Jason Merrill wrote:

> On 2/25/21 1:37 AM, Patrick Palka wrote:
> > In-Reply-To: <20210225063712.3725111-1-ppa...@redhat.com>
> 
> BTW, This patch doesn't seem in any way a reply to your previous patch, so
> it's confusing for the mail headers (and thus MUA threading) to say that it
> is.  Maybe you want git send-email --no-thread or
> git config sendemail.thread false ?

Ah, thanks for the heads up.  Out of convenience I sent these two
unrelated patches via a single "git send-email" command, which
unknowingly caused the second patch to get sent as reply to the first.
I'll make sure to send unrelated patches via separate send-email
commands, or via a single command but with --no-thread.

> 
> > In the three-parameter version of satisfy_declaration_constraints, when
> > 't' isn't the most general template, then 't' doesn't correspond with
> > the augmented template arguments 'args', and so the instantiation
> > context that we push via push_tinst_level isn't quite correct.  This
> > manifests as misleading diagnostic context lines during satisfaction
> > failure as in the testcase below for which without this patch we emit
> >    In substitution of '... static void A<int>::f<U>() [with U = int]'
> > and with this patch we emit
> >    In substitution of '... static void A<T>::f<U>() [with U = char; T =
> > int]'.
> > 
> > This patch fixes this by passing the most general template to
> > push_tinst_level.
> > 
> > Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
> > trunk?
> 
> > gcc/cp/ChangeLog:
> > 
> >     PR c++/99214
> >     * constraint.cc (get_normalized_constraints_from_decl): Fix
> >     formatting.
> >     (satisfy_declaration_constraints): Be lazy about augmenting
> >     'args'.  Pass the most general template to push_tinst_level.
> > 
> > gcc/testsuite/ChangeLog:
> > 
> >     PR c++/99214
> >     * g++.dg/concepts/diagnostic16.C: New test.
> > ---
> >   gcc/cp/constraint.cc                         | 16 ++++++++--------
> >   gcc/testsuite/g++.dg/concepts/diagnostic16.C | 15 +++++++++++++++
> >   2 files changed, 23 insertions(+), 8 deletions(-)
> >   create mode 100644 gcc/testsuite/g++.dg/concepts/diagnostic16.C
> > 
> > diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
> > index 31e0fb5079a..88963e687a7 100644
> > --- a/gcc/cp/constraint.cc
> > +++ b/gcc/cp/constraint.cc
> > @@ -910,11 +910,9 @@ get_normalized_constraints_from_decl (tree d, bool diag
> > = false)
> >        accepting the latter causes the template parameter level of U
> >        to be reduced in a way that makes it overly difficult substitute
> >        concrete arguments (i.e., eventually {int, int} during satisfaction.
> > */
> > -  if (tmpl)
> > -  {
> > -    if (DECL_LANG_SPECIFIC(tmpl) && !DECL_TEMPLATE_SPECIALIZATION (tmpl))
> > -      tmpl = most_general_template (tmpl);
> > -  }
> > +  if (tmpl && DECL_LANG_SPECIFIC (tmpl)
> > +      && !DECL_TEMPLATE_SPECIALIZATION (tmpl))
> > +    tmpl = most_general_template (tmpl);
> 
> Can we use template_for_substitution instead of checking
> DECL_TEMPLATE_SPECIALIZATION and most_general_template?  That seems to be the
> semantic we want.

That sounds promising.  I tried (roughly)

diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 88963e687a7..1d974c52911 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -910,9 +910,7 @@ get_normalized_constraints_from_decl (tree d, bool diag = 
false)
      accepting the latter causes the template parameter level of U
      to be reduced in a way that makes it overly difficult substitute
      concrete arguments (i.e., eventually {int, int} during satisfaction.  */
-  if (tmpl && DECL_LANG_SPECIFIC (tmpl)
-      && !DECL_TEMPLATE_SPECIALIZATION (tmpl))
-    tmpl = most_general_template (tmpl);
+  tmpl = template_for_substitution (decl);
 
   /* If we're not diagnosing errors, use cached constraints, if any.  */
   if (!diag)

which breaks a lot of tests due to trivial reasons (e.g. DECL_LANG_SPECIFIC
being empty), but in particular it breaks g++.dg/cpp2a/concepts-partial-spec2.C
in a non-trivial way.  In this testcase, the TEMPLATE_DECL for the
partial specialization

  template <class T>
    requires True<T> && (T() == 0)
  constexpr bool p<T*> = true;

has as its DECL_TEMPLATE_RESULT a VAR_DECL whose DECL_TI_TEMPLATE is
the TEMPLATE_DECL not for the above partial specialization but for
the primary template for p.

So in short, when calling get_normalized_constraints_from_decl on the
above TEMPLATE_DECL we have

  tmpl = d
  decl = DECL_TEMPLATE_RESULT(tmpl)
  most_general_template(tmpl) == tmpl == the partial specialization
  template_for_substitution(decl) == decl == the primary template

and hence using template_for_substitution instead of
most_general_template here would cause us to normalize the wrong
constraints.

> 
> >     /* If we're not diagnosing errors, use cached constraints, if any.  */
> >     if (!diag)
> > @@ -3157,12 +3155,14 @@ satisfy_declaration_constraints (tree t, tree args,
> > sat_info info)
> >       gcc_assert (TREE_CODE (t) == TEMPLATE_DECL);
> >   -  args = add_outermost_template_args (t, args);
> > -
> >     tree result = boolean_true_node;
> >     if (tree norm = normalize_template_requirements (t, info.noisy ()))
> >       {
> > -      if (!push_tinst_level (t, args))
> > +      args = add_outermost_template_args (t, args);
> > +      tree gen_tmpl = t;
> > +      if (DECL_LANG_SPECIFIC (t) && !DECL_TEMPLATE_SPECIALIZATION (t))
> > +   gen_tmpl = most_general_template (t);
> > +      if (!push_tinst_level (gen_tmpl, args))
> >     return result;
> >         tree pattern = DECL_TEMPLATE_RESULT (t);
> >         push_access_scope (pattern);
> > diff --git a/gcc/testsuite/g++.dg/concepts/diagnostic16.C
> > b/gcc/testsuite/g++.dg/concepts/diagnostic16.C
> > new file mode 100644
> > index 00000000000..b8d586e9a21
> > --- /dev/null
> > +++ b/gcc/testsuite/g++.dg/concepts/diagnostic16.C
> > @@ -0,0 +1,15 @@
> > +// PR c++/99214
> > +// { dg-do compile { target c++20 } }
> > +
> > +template <class T>
> > +struct A {
> > +  template <class U> static void f() requires ([] { return U::fail; }());
> > // { dg-error "fail" }
> > +  template <class U> static void f();
> > +};
> > +
> > +int main() {
> > +  A<int>::f<char>();
> > +}
> > +
> > +// This matches the context line "In substitution of '... [with U = char; T
> > = int]'"
> > +// { dg-message "U = char; T = int" "" { target *-*-* } 0 }
> > 
> 
> 

Reply via email to