diff mbox series

c++: cv-qualified dependent name of alias tmpl [PR100592]

Message ID 20210602183934.958366-1-ppalka@redhat.com
State New
Headers show
Series c++: cv-qualified dependent name of alias tmpl [PR100592] | expand

Commit Message

Patrick Palka June 2, 2021, 6:39 p.m. UTC
Here, the dependent template name in the return type of f() resolves to
an alias of int& after substitution, and we end up complaining about
qualifying this reference type with 'const' from cp_build_qualified_type
rather than just silently dropping the qualification as per [dcl.ref]/1.

We already have the tf_ignore_bad_quals flag for this situation, but
the TYPENAME_TYPE branch of tsubst for some reason doesn't always use
this flag.  This patch just makes tsubst unconditionally use this flag
when substituting a TYPENAME_TYPE.

This change also causes us to drop bogus __restrict__ qualifiers more
consistently during substitution, as in qualttp20.C below where we no
longer diagnose the __restrict__ qualifier on B1<AS>::r.  Note that if
we artificially introduced a typedef as in B1<AS>::s we silently dropped
__restrict__ even before this patch, so this seems like an improvement.

Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
trunk?

	PR c++/100592

gcc/cp/ChangeLog:

	* pt.c (tsubst) <case TYPENAME_TYPE>: Always pass
	tf_ignore_bad_quals to cp_build_qualified_type.

gcc/testsuite/ChangeLog:

	* g++.dg/cpp0x/alias-decl-71.C: New test.
	* g++.dg/template/qualttp20.C: Remove dg-error and augment.
---
 gcc/cp/pt.c                                | 10 ++++------
 gcc/testsuite/g++.dg/cpp0x/alias-decl-71.C | 13 +++++++++++++
 gcc/testsuite/g++.dg/template/qualttp20.C  |  6 ++++--
 3 files changed, 21 insertions(+), 8 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp0x/alias-decl-71.C

Comments

Jason Merrill June 2, 2021, 7:55 p.m. UTC | #1
On 6/2/21 2:39 PM, Patrick Palka wrote:
> Here, the dependent template name in the return type of f() resolves to
> an alias of int& after substitution, and we end up complaining about
> qualifying this reference type with 'const' from cp_build_qualified_type
> rather than just silently dropping the qualification as per [dcl.ref]/1.

Hmm, the patch looks fine, but why does the TYPE_DECL test fail for the 
alias?

> We already have the tf_ignore_bad_quals flag for this situation, but
> the TYPENAME_TYPE branch of tsubst for some reason doesn't always use
> this flag.  This patch just makes tsubst unconditionally use this flag
> when substituting a TYPENAME_TYPE.
> 
> This change also causes us to drop bogus __restrict__ qualifiers more
> consistently during substitution, as in qualttp20.C below where we no
> longer diagnose the __restrict__ qualifier on B1<AS>::r.  Note that if
> we artificially introduced a typedef as in B1<AS>::s we silently dropped
> __restrict__ even before this patch, so this seems like an improvement.
> 
> Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
> trunk?
> 
> 	PR c++/100592
> 
> gcc/cp/ChangeLog:
> 
> 	* pt.c (tsubst) <case TYPENAME_TYPE>: Always pass
> 	tf_ignore_bad_quals to cp_build_qualified_type.
> 
> gcc/testsuite/ChangeLog:
> 
> 	* g++.dg/cpp0x/alias-decl-71.C: New test.
> 	* g++.dg/template/qualttp20.C: Remove dg-error and augment.
> ---
>   gcc/cp/pt.c                                | 10 ++++------
>   gcc/testsuite/g++.dg/cpp0x/alias-decl-71.C | 13 +++++++++++++
>   gcc/testsuite/g++.dg/template/qualttp20.C  |  6 ++++--
>   3 files changed, 21 insertions(+), 8 deletions(-)
>   create mode 100644 gcc/testsuite/g++.dg/cpp0x/alias-decl-71.C
> 
> diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
> index 86259e900e9..2da5407a2a7 100644
> --- a/gcc/cp/pt.c
> +++ b/gcc/cp/pt.c
> @@ -16066,10 +16066,7 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl)
>   	if (f == error_mark_node)
>   	  return f;
>   	if (TREE_CODE (f) == TYPE_DECL)
> -	  {
> -	    complain |= tf_ignore_bad_quals;
> -	    f = TREE_TYPE (f);
> -	  }
> +	  f = TREE_TYPE (f);
>   
>   	if (TREE_CODE (f) != TYPENAME_TYPE)
>   	  {
> @@ -16091,8 +16088,9 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl)
>   	      }
>   	  }
>   
> -	return cp_build_qualified_type_real
> -	  (f, cp_type_quals (f) | cp_type_quals (t), complain);
> +	int quals = cp_type_quals (f) | cp_type_quals (t);
> +	complain |= tf_ignore_bad_quals;
> +	return cp_build_qualified_type_real (f, quals, complain);
>         }
>   
>       case UNBOUND_CLASS_TEMPLATE:
> diff --git a/gcc/testsuite/g++.dg/cpp0x/alias-decl-71.C b/gcc/testsuite/g++.dg/cpp0x/alias-decl-71.C
> new file mode 100644
> index 00000000000..6a61f93a0b0
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp0x/alias-decl-71.C
> @@ -0,0 +1,13 @@
> +// PR c++/100592
> +// { dg-do compile { target c++11 } }
> +
> +template<bool>
> +struct meta {
> +  template<class> using if_c = int&;
> +};
> +
> +template<bool B>
> +typename meta<B>::template if_c<void> const f();
> +
> +using type = decltype(f<true>());
> +using type = int&;
> diff --git a/gcc/testsuite/g++.dg/template/qualttp20.C b/gcc/testsuite/g++.dg/template/qualttp20.C
> index 52989bae538..3281f5d9eab 100644
> --- a/gcc/testsuite/g++.dg/template/qualttp20.C
> +++ b/gcc/testsuite/g++.dg/template/qualttp20.C
> @@ -10,13 +10,15 @@ struct AS
>   {
>     typedef void (myT) ();
>     struct L {};
> +  typedef struct {} M;
>     
>   };
>   
>   
>   template <typename T> struct B1 : T
>   {
> -  typedef typename T::L __restrict__ r;// { dg-error "'__restrict__' qualifiers cannot" }
> +  typedef typename T::L __restrict__ r;
> +  typedef typename T::M __restrict__ s;
>     typedef typename T::myT __restrict__ p;
>   
>     // The following are DR 295 dependent
> @@ -32,5 +34,5 @@ template <typename T> struct B2 : T
>     myconst b;
>   };
>   
> -B1<AS> b1;	// { dg-message "required" }
> +B1<AS> b1;
>   B2<AS> b2;
>
Patrick Palka June 2, 2021, 8:50 p.m. UTC | #2
On Wed, 2 Jun 2021, Jason Merrill wrote:

> On 6/2/21 2:39 PM, Patrick Palka wrote:
> > Here, the dependent template name in the return type of f() resolves to
> > an alias of int& after substitution, and we end up complaining about
> > qualifying this reference type with 'const' from cp_build_qualified_type
> > rather than just silently dropping the qualification as per [dcl.ref]/1.
> 
> Hmm, the patch looks fine, but why does the TYPE_DECL test fail for the alias?

Ah, I hadn't considered investigating that.  It seems make_typename_type
always returns a _TYPE instead of a TYPE_DECL when resolving a dependent
name that's a template-id, regardless of the tf_keep_type_decl flag.
This can be easily fixed like so, and this change alone is sufficient to
fix the PR (no changes to qualttp20.C needed).  Note that this change
should only have an effect when tf_keep_type_decl is passed to
make_typename_type, and the only such caller is the TYPENAME_TYPE case
of tsubst in question, so this change seems pretty safe.

The downside is that we don't get the __restrict__-dropping
"improvement" as exhibited by qualttp20.C that the original patch
provides, so this other approach is more conservative in that sense.

So shall we go with the original patch, or something like the following?
(If we go with the original patch, it just occurred to me that we could
remove tf_keep_type_decl altogether.)  Testing in progress.

-- >8 --

diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index fb21a3a1ae8..1be232af483 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -4136,10 +4136,15 @@ make_typename_type (tree context, tree name, enum tag_types tag_type,
     return error_mark_node;

   if (want_template)
-    return lookup_template_class (t, TREE_OPERAND (fullname, 1),
-                                 NULL_TREE, context,
-                                 /*entering_scope=*/0,
-                                 complain | tf_user);
+    {
+      t = lookup_template_class (t, TREE_OPERAND (fullname, 1),
+                                NULL_TREE, context,
+                                /*entering_scope=*/0,
+                                complain | tf_user);
+      if (!TYPE_P (t))
+       return t;
+      t = TYPE_NAME (t);
+    }

   if (DECL_ARTIFICIAL (t) || !(complain & tf_keep_type_decl))
     t = TREE_TYPE (t);
Patrick Palka June 2, 2021, 8:56 p.m. UTC | #3
On Wed, 2 Jun 2021, Patrick Palka wrote:

> On Wed, 2 Jun 2021, Jason Merrill wrote:
> 
> > On 6/2/21 2:39 PM, Patrick Palka wrote:
> > > Here, the dependent template name in the return type of f() resolves to
> > > an alias of int& after substitution, and we end up complaining about
> > > qualifying this reference type with 'const' from cp_build_qualified_type
> > > rather than just silently dropping the qualification as per [dcl.ref]/1.
> > 
> > Hmm, the patch looks fine, but why does the TYPE_DECL test fail for the alias?
> 
> Ah, I hadn't considered investigating that.  It seems make_typename_type
> always returns a _TYPE instead of a TYPE_DECL when resolving a dependent
> name that's a template-id, regardless of the tf_keep_type_decl flag.
> This can be easily fixed like so, and this change alone is sufficient to
> fix the PR (no changes to qualttp20.C needed).  Note that this change
> should only have an effect when tf_keep_type_decl is passed to
> make_typename_type, and the only such caller is the TYPENAME_TYPE case
> of tsubst in question, so this change seems pretty safe.
> 
> The downside is that we don't get the __restrict__-dropping
> "improvement" as exhibited by qualttp20.C that the original patch
> provides, so this other approach is more conservative in that sense.
> 
> So shall we go with the original patch, or something like the following?
> (If we go with the original patch, it just occurred to me that we could
> remove tf_keep_type_decl altogether.)  Testing in progress.

For sake of concreteness, here's the full alternative patch for
consideration (modulo ChangeLog):

-- >8 --

---
 gcc/cp/decl.c                              | 13 +++++++++----
 gcc/testsuite/g++.dg/cpp0x/alias-decl-71.C | 13 +++++++++++++
 2 files changed, 22 insertions(+), 4 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp0x/alias-decl-71.C

diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index fb21a3a1ae8..1be232af483 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -4136,10 +4136,15 @@ make_typename_type (tree context, tree name, enum tag_types tag_type,
     return error_mark_node;
 
   if (want_template)
-    return lookup_template_class (t, TREE_OPERAND (fullname, 1),
-				  NULL_TREE, context,
-				  /*entering_scope=*/0,
-				  complain | tf_user);
+    {
+      t = lookup_template_class (t, TREE_OPERAND (fullname, 1),
+				 NULL_TREE, context,
+				 /*entering_scope=*/0,
+				 complain | tf_user);
+      if (!TYPE_P (t))
+	return t;
+      t = TYPE_NAME (t);
+    }
   
   if (DECL_ARTIFICIAL (t) || !(complain & tf_keep_type_decl))
     t = TREE_TYPE (t);
diff --git a/gcc/testsuite/g++.dg/cpp0x/alias-decl-71.C b/gcc/testsuite/g++.dg/cpp0x/alias-decl-71.C
new file mode 100644
index 00000000000..6a61f93a0b0
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/alias-decl-71.C
@@ -0,0 +1,13 @@
+// PR c++/100592
+// { dg-do compile { target c++11 } }
+
+template<bool>
+struct meta {
+  template<class> using if_c = int&;
+};
+
+template<bool B>
+typename meta<B>::template if_c<void> const f();
+
+using type = decltype(f<true>());
+using type = int&;
Jason Merrill June 2, 2021, 9:37 p.m. UTC | #4
On 6/2/21 4:56 PM, Patrick Palka wrote:
> On Wed, 2 Jun 2021, Patrick Palka wrote:
> 
>> On Wed, 2 Jun 2021, Jason Merrill wrote:
>>
>>> On 6/2/21 2:39 PM, Patrick Palka wrote:
>>>> Here, the dependent template name in the return type of f() resolves to
>>>> an alias of int& after substitution, and we end up complaining about
>>>> qualifying this reference type with 'const' from cp_build_qualified_type
>>>> rather than just silently dropping the qualification as per [dcl.ref]/1.
>>>
>>> Hmm, the patch looks fine, but why does the TYPE_DECL test fail for the alias?
>>
>> Ah, I hadn't considered investigating that.  It seems make_typename_type
>> always returns a _TYPE instead of a TYPE_DECL when resolving a dependent
>> name that's a template-id, regardless of the tf_keep_type_decl flag.
>> This can be easily fixed like so, and this change alone is sufficient to
>> fix the PR (no changes to qualttp20.C needed).  Note that this change
>> should only have an effect when tf_keep_type_decl is passed to
>> make_typename_type, and the only such caller is the TYPENAME_TYPE case
>> of tsubst in question, so this change seems pretty safe.
>>
>> The downside is that we don't get the __restrict__-dropping
>> "improvement" as exhibited by qualttp20.C that the original patch
>> provides, so this other approach is more conservative in that sense.
>>
>> So shall we go with the original patch, or something like the following?
>> (If we go with the original patch, it just occurred to me that we could
>> remove tf_keep_type_decl altogether.)  Testing in progress.
> 
> For sake of concreteness, here's the full alternative patch for
> consideration (modulo ChangeLog):

This seems better.  I think the only non-type return from 
lookup_template_class is error_mark_node; does it work to check that 
specifically rather than !TYPE_P?

> -- >8 --
> 
> ---
>   gcc/cp/decl.c                              | 13 +++++++++----
>   gcc/testsuite/g++.dg/cpp0x/alias-decl-71.C | 13 +++++++++++++
>   2 files changed, 22 insertions(+), 4 deletions(-)
>   create mode 100644 gcc/testsuite/g++.dg/cpp0x/alias-decl-71.C
> 
> diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
> index fb21a3a1ae8..1be232af483 100644
> --- a/gcc/cp/decl.c
> +++ b/gcc/cp/decl.c
> @@ -4136,10 +4136,15 @@ make_typename_type (tree context, tree name, enum tag_types tag_type,
>       return error_mark_node;
>   
>     if (want_template)
> -    return lookup_template_class (t, TREE_OPERAND (fullname, 1),
> -				  NULL_TREE, context,
> -				  /*entering_scope=*/0,
> -				  complain | tf_user);
> +    {
> +      t = lookup_template_class (t, TREE_OPERAND (fullname, 1),
> +				 NULL_TREE, context,
> +				 /*entering_scope=*/0,
> +				 complain | tf_user);
> +      if (!TYPE_P (t))
> +	return t;
> +      t = TYPE_NAME (t);
> +    }
>     
>     if (DECL_ARTIFICIAL (t) || !(complain & tf_keep_type_decl))
>       t = TREE_TYPE (t);
> diff --git a/gcc/testsuite/g++.dg/cpp0x/alias-decl-71.C b/gcc/testsuite/g++.dg/cpp0x/alias-decl-71.C
> new file mode 100644
> index 00000000000..6a61f93a0b0
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp0x/alias-decl-71.C
> @@ -0,0 +1,13 @@
> +// PR c++/100592
> +// { dg-do compile { target c++11 } }
> +
> +template<bool>
> +struct meta {
> +  template<class> using if_c = int&;
> +};
> +
> +template<bool B>
> +typename meta<B>::template if_c<void> const f();
> +
> +using type = decltype(f<true>());
> +using type = int&;
>
Patrick Palka June 2, 2021, 11:05 p.m. UTC | #5
On Wed, 2 Jun 2021, Jason Merrill wrote:

> On 6/2/21 4:56 PM, Patrick Palka wrote:
> > On Wed, 2 Jun 2021, Patrick Palka wrote:
> > 
> > > On Wed, 2 Jun 2021, Jason Merrill wrote:
> > > 
> > > > On 6/2/21 2:39 PM, Patrick Palka wrote:
> > > > > Here, the dependent template name in the return type of f() resolves
> > > > > to
> > > > > an alias of int& after substitution, and we end up complaining about
> > > > > qualifying this reference type with 'const' from
> > > > > cp_build_qualified_type
> > > > > rather than just silently dropping the qualification as per
> > > > > [dcl.ref]/1.
> > > > 
> > > > Hmm, the patch looks fine, but why does the TYPE_DECL test fail for the
> > > > alias?
> > > 
> > > Ah, I hadn't considered investigating that.  It seems make_typename_type
> > > always returns a _TYPE instead of a TYPE_DECL when resolving a dependent
> > > name that's a template-id, regardless of the tf_keep_type_decl flag.
> > > This can be easily fixed like so, and this change alone is sufficient to
> > > fix the PR (no changes to qualttp20.C needed).  Note that this change
> > > should only have an effect when tf_keep_type_decl is passed to
> > > make_typename_type, and the only such caller is the TYPENAME_TYPE case
> > > of tsubst in question, so this change seems pretty safe.
> > > 
> > > The downside is that we don't get the __restrict__-dropping
> > > "improvement" as exhibited by qualttp20.C that the original patch
> > > provides, so this other approach is more conservative in that sense.
> > > 
> > > So shall we go with the original patch, or something like the following?
> > > (If we go with the original patch, it just occurred to me that we could
> > > remove tf_keep_type_decl altogether.)  Testing in progress.
> > 
> > For sake of concreteness, here's the full alternative patch for
> > consideration (modulo ChangeLog):
> 
> This seems better.  I think the only non-type return from
> lookup_template_class is error_mark_node; does it work to check that
> specifically rather than !TYPE_P?

Indeed, checking for error_mark_node instead works nicely.  Does the
following look OK?  Bootstrapped and regtested on x86_64-pc-linux-gnu.

-- >8 --

Subject: [PATCH] c++: cv-qualified dependent name of alias tmpl [PR100592]

Here, the dependent template name in the return type of f() resolves to
an alias of int& after substitution, and we end up complaining about
qualifying this reference type with 'const' from cp_build_qualified_type
rather than just silently dropping the qualification as per [dcl.ref]/1.

The problem is ultimately that make_typename_type ignores the
tf_keep_type_decl flag when the dependent name is a template-id.  This
in turn causes the TYPE_DECL check within tsubst <case TYPENAME_TYPE>
to fail, and so we end up not passing tf_ignore_bad_quals to
cp_build_qualified_type.  This patch fixes this by making
make_typename_type respect the tf_keep_type_decl flag even in the case
of a dependent template-id name.

Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
trunk?

	PR c++/100592

gcc/cp/ChangeLog:

	* decl.c (make_typename_type): After dispatching to
	lookup_template_class, adjust the result to its TYPE_NAME
	and then consider the tf_keep_type_decl flag.

gcc/testsuite/ChangeLog:

	* g++.dg/cpp0x/alias-decl-71.C: New test.
	* g++.dg/template/qualttp20.C: Remove dg-error and augment.
---
 gcc/cp/decl.c                              | 13 +++++++++----
 gcc/testsuite/g++.dg/cpp0x/alias-decl-71.C | 13 +++++++++++++
 2 files changed, 22 insertions(+), 4 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp0x/alias-decl-71.C

diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index fb21a3a1ae8..a3687dbb0dd 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -4136,10 +4136,15 @@ make_typename_type (tree context, tree name, enum tag_types tag_type,
     return error_mark_node;
 
   if (want_template)
-    return lookup_template_class (t, TREE_OPERAND (fullname, 1),
-				  NULL_TREE, context,
-				  /*entering_scope=*/0,
-				  complain | tf_user);
+    {
+      t = lookup_template_class (t, TREE_OPERAND (fullname, 1),
+				 NULL_TREE, context,
+				 /*entering_scope=*/0,
+				 complain | tf_user);
+      if (t == error_mark_node)
+	return error_mark_node;
+      t = TYPE_NAME (t);
+    }
   
   if (DECL_ARTIFICIAL (t) || !(complain & tf_keep_type_decl))
     t = TREE_TYPE (t);
diff --git a/gcc/testsuite/g++.dg/cpp0x/alias-decl-71.C b/gcc/testsuite/g++.dg/cpp0x/alias-decl-71.C
new file mode 100644
index 00000000000..6a61f93a0b0
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/alias-decl-71.C
@@ -0,0 +1,13 @@
+// PR c++/100592
+// { dg-do compile { target c++11 } }
+
+template<bool>
+struct meta {
+  template<class> using if_c = int&;
+};
+
+template<bool B>
+typename meta<B>::template if_c<void> const f();
+
+using type = decltype(f<true>());
+using type = int&;
Jason Merrill June 3, 2021, 3:55 a.m. UTC | #6
On 6/2/21 7:05 PM, Patrick Palka wrote:
> On Wed, 2 Jun 2021, Jason Merrill wrote:
> 
>> On 6/2/21 4:56 PM, Patrick Palka wrote:
>>> On Wed, 2 Jun 2021, Patrick Palka wrote:
>>>
>>>> On Wed, 2 Jun 2021, Jason Merrill wrote:
>>>>
>>>>> On 6/2/21 2:39 PM, Patrick Palka wrote:
>>>>>> Here, the dependent template name in the return type of f() resolves
>>>>>> to
>>>>>> an alias of int& after substitution, and we end up complaining about
>>>>>> qualifying this reference type with 'const' from
>>>>>> cp_build_qualified_type
>>>>>> rather than just silently dropping the qualification as per
>>>>>> [dcl.ref]/1.
>>>>>
>>>>> Hmm, the patch looks fine, but why does the TYPE_DECL test fail for the
>>>>> alias?
>>>>
>>>> Ah, I hadn't considered investigating that.  It seems make_typename_type
>>>> always returns a _TYPE instead of a TYPE_DECL when resolving a dependent
>>>> name that's a template-id, regardless of the tf_keep_type_decl flag.
>>>> This can be easily fixed like so, and this change alone is sufficient to
>>>> fix the PR (no changes to qualttp20.C needed).  Note that this change
>>>> should only have an effect when tf_keep_type_decl is passed to
>>>> make_typename_type, and the only such caller is the TYPENAME_TYPE case
>>>> of tsubst in question, so this change seems pretty safe.
>>>>
>>>> The downside is that we don't get the __restrict__-dropping
>>>> "improvement" as exhibited by qualttp20.C that the original patch
>>>> provides, so this other approach is more conservative in that sense.
>>>>
>>>> So shall we go with the original patch, or something like the following?
>>>> (If we go with the original patch, it just occurred to me that we could
>>>> remove tf_keep_type_decl altogether.)  Testing in progress.
>>>
>>> For sake of concreteness, here's the full alternative patch for
>>> consideration (modulo ChangeLog):
>>
>> This seems better.  I think the only non-type return from
>> lookup_template_class is error_mark_node; does it work to check that
>> specifically rather than !TYPE_P?
> 
> Indeed, checking for error_mark_node instead works nicely.  Does the
> following look OK?  Bootstrapped and regtested on x86_64-pc-linux-gnu.

OK.

> -- >8 --
> 
> Subject: [PATCH] c++: cv-qualified dependent name of alias tmpl [PR100592]
> 
> Here, the dependent template name in the return type of f() resolves to
> an alias of int& after substitution, and we end up complaining about
> qualifying this reference type with 'const' from cp_build_qualified_type
> rather than just silently dropping the qualification as per [dcl.ref]/1.
> 
> The problem is ultimately that make_typename_type ignores the
> tf_keep_type_decl flag when the dependent name is a template-id.  This
> in turn causes the TYPE_DECL check within tsubst <case TYPENAME_TYPE>
> to fail, and so we end up not passing tf_ignore_bad_quals to
> cp_build_qualified_type.  This patch fixes this by making
> make_typename_type respect the tf_keep_type_decl flag even in the case
> of a dependent template-id name.
> 
> Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
> trunk?
> 
> 	PR c++/100592
> 
> gcc/cp/ChangeLog:
> 
> 	* decl.c (make_typename_type): After dispatching to
> 	lookup_template_class, adjust the result to its TYPE_NAME
> 	and then consider the tf_keep_type_decl flag.
> 
> gcc/testsuite/ChangeLog:
> 
> 	* g++.dg/cpp0x/alias-decl-71.C: New test.
> 	* g++.dg/template/qualttp20.C: Remove dg-error and augment.
> ---
>   gcc/cp/decl.c                              | 13 +++++++++----
>   gcc/testsuite/g++.dg/cpp0x/alias-decl-71.C | 13 +++++++++++++
>   2 files changed, 22 insertions(+), 4 deletions(-)
>   create mode 100644 gcc/testsuite/g++.dg/cpp0x/alias-decl-71.C
> 
> diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
> index fb21a3a1ae8..a3687dbb0dd 100644
> --- a/gcc/cp/decl.c
> +++ b/gcc/cp/decl.c
> @@ -4136,10 +4136,15 @@ make_typename_type (tree context, tree name, enum tag_types tag_type,
>       return error_mark_node;
>   
>     if (want_template)
> -    return lookup_template_class (t, TREE_OPERAND (fullname, 1),
> -				  NULL_TREE, context,
> -				  /*entering_scope=*/0,
> -				  complain | tf_user);
> +    {
> +      t = lookup_template_class (t, TREE_OPERAND (fullname, 1),
> +				 NULL_TREE, context,
> +				 /*entering_scope=*/0,
> +				 complain | tf_user);
> +      if (t == error_mark_node)
> +	return error_mark_node;
> +      t = TYPE_NAME (t);
> +    }
>     
>     if (DECL_ARTIFICIAL (t) || !(complain & tf_keep_type_decl))
>       t = TREE_TYPE (t);
> diff --git a/gcc/testsuite/g++.dg/cpp0x/alias-decl-71.C b/gcc/testsuite/g++.dg/cpp0x/alias-decl-71.C
> new file mode 100644
> index 00000000000..6a61f93a0b0
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp0x/alias-decl-71.C
> @@ -0,0 +1,13 @@
> +// PR c++/100592
> +// { dg-do compile { target c++11 } }
> +
> +template<bool>
> +struct meta {
> +  template<class> using if_c = int&;
> +};
> +
> +template<bool B>
> +typename meta<B>::template if_c<void> const f();
> +
> +using type = decltype(f<true>());
> +using type = int&;
>
diff mbox series

Patch

diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 86259e900e9..2da5407a2a7 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -16066,10 +16066,7 @@  tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl)
 	if (f == error_mark_node)
 	  return f;
 	if (TREE_CODE (f) == TYPE_DECL)
-	  {
-	    complain |= tf_ignore_bad_quals;
-	    f = TREE_TYPE (f);
-	  }
+	  f = TREE_TYPE (f);
 
 	if (TREE_CODE (f) != TYPENAME_TYPE)
 	  {
@@ -16091,8 +16088,9 @@  tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl)
 	      }
 	  }
 
-	return cp_build_qualified_type_real
-	  (f, cp_type_quals (f) | cp_type_quals (t), complain);
+	int quals = cp_type_quals (f) | cp_type_quals (t);
+	complain |= tf_ignore_bad_quals;
+	return cp_build_qualified_type_real (f, quals, complain);
       }
 
     case UNBOUND_CLASS_TEMPLATE:
diff --git a/gcc/testsuite/g++.dg/cpp0x/alias-decl-71.C b/gcc/testsuite/g++.dg/cpp0x/alias-decl-71.C
new file mode 100644
index 00000000000..6a61f93a0b0
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/alias-decl-71.C
@@ -0,0 +1,13 @@ 
+// PR c++/100592
+// { dg-do compile { target c++11 } }
+
+template<bool>
+struct meta {
+  template<class> using if_c = int&;
+};
+
+template<bool B>
+typename meta<B>::template if_c<void> const f();
+
+using type = decltype(f<true>());
+using type = int&;
diff --git a/gcc/testsuite/g++.dg/template/qualttp20.C b/gcc/testsuite/g++.dg/template/qualttp20.C
index 52989bae538..3281f5d9eab 100644
--- a/gcc/testsuite/g++.dg/template/qualttp20.C
+++ b/gcc/testsuite/g++.dg/template/qualttp20.C
@@ -10,13 +10,15 @@  struct AS
 {
   typedef void (myT) ();
   struct L {};
+  typedef struct {} M;
   
 };
 
 
 template <typename T> struct B1 : T
 {
-  typedef typename T::L __restrict__ r;// { dg-error "'__restrict__' qualifiers cannot" }
+  typedef typename T::L __restrict__ r;
+  typedef typename T::M __restrict__ s;
   typedef typename T::myT __restrict__ p;
 
   // The following are DR 295 dependent
@@ -32,5 +34,5 @@  template <typename T> struct B2 : T
   myconst b;
 };
 
-B1<AS> b1;	// { dg-message "required" }
+B1<AS> b1;
 B2<AS> b2;