Patchwork PR c++/54875 - Error when instantiating an alias template that resolves to an enum

login
register
mail settings
Submitter Dodji Seketeli
Date Nov. 16, 2012, 12:43 p.m.
Message ID <87lie1vhti.fsf@redhat.com>
Download mbox | patch
Permalink /patch/199569/
State New
Headers show

Comments

Dodji Seketeli - Nov. 16, 2012, 12:43 p.m.
Hello,

Consider this short example:

     1	template<typename T>
     2	using AddConst = T const;
     3
     4	enum FwdEnum : int;
     5
     6	int main() {
     7	  AddConst<FwdEnum> *ptr = nullptr;
     8	}

At line 7, when we build the type for AddConst<FwdEnum> in
lookup_template_class_1, the resulting type is the enum FwdEnum.  This
confuses lookup_template_class_1 near the if below, wrongly making it
taking the branch and thus calling tsubst_enum while it shouldn't:

      if (TREE_CODE (t) == ENUMERAL_TYPE && !is_dependent_type)
	/* Now that the type has been registered on the instantiations
	   list, we set up the enumerators.  Because the enumeration
	   constants may involve the enumeration type itself, we make
	   sure to register the type first, and then create the
	   constants.  That way, doing tsubst_expr for the enumeration
	   constants won't result in recursive calls here; we'll find
	   the instantiation and exit above.  */
	tsubst_enum (template_type, t, arglist);

Before the alias template feature, the only reason why TREE_CODE (t)
== ENUMERAL_TYPE would be true is when lookup_template_class_1 is
called for an enum that is a member of a class template.  But that
condition can be also true for an alias template instantiation as
well.

So I guess that condition should be changed to TREE_CODE
(template_type) == ENUMERAL_TYPE, to specifically detect the member
enum of a class template case.

This is what the one-liner patchlet below does.

Bootstrapped and tested on x86_64-unknown-linux-gnu against trunk.

gcc/cp/

	* pt.c (lookup_template_class_1): Look at the type of the
	potential member enum of class template to determine if we are
	actually substituting into a member enum of class template.

gcc/testsuite/

	* g++.dg/cpp0x/alias-decl-27.C: New test.
---
 gcc/cp/pt.c                                |  2 +-
 gcc/testsuite/g++.dg/cpp0x/alias-decl-27.C | 11 +++++++++++
 2 files changed, 12 insertions(+), 1 deletion(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp0x/alias-decl-27.C
Jason Merrill - Nov. 16, 2012, 1:51 p.m.
On 11/16/2012 07:43 AM, Dodji Seketeli wrote:
> So I guess that condition should be changed to TREE_CODE
> (template_type) == ENUMERAL_TYPE, to specifically detect the member
> enum of a class template case.

Why does that help?  What is template_type in the alias template case?

Jason
Dodji Seketeli - Nov. 16, 2012, 2:10 p.m.
Jason Merrill <jason@redhat.com> writes:

> On 11/16/2012 07:43 AM, Dodji Seketeli wrote:
>> So I guess that condition should be changed to TREE_CODE
>> (template_type) == ENUMERAL_TYPE, to specifically detect the member
>> enum of a class template case.
>
> Why does that help?  What is template_type in the alias template case?

template_type is the template_type_parm T, which new name is AddConst.
Jason Merrill - Nov. 16, 2012, 2:43 p.m.
Ah, I see.  OK.

Jason

Patch

diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 3c9bb56..101b22d 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -7487,7 +7487,7 @@  lookup_template_class_1 (tree d1, tree arglist, tree in_decl, tree context,
 	= tree_cons (arglist, t,
 		     DECL_TEMPLATE_INSTANTIATIONS (templ));
 
-      if (TREE_CODE (t) == ENUMERAL_TYPE && !is_dependent_type)
+      if (TREE_CODE (template_type) == ENUMERAL_TYPE && !is_dependent_type)
 	/* Now that the type has been registered on the instantiations
 	   list, we set up the enumerators.  Because the enumeration
 	   constants may involve the enumeration type itself, we make
diff --git a/gcc/testsuite/g++.dg/cpp0x/alias-decl-27.C b/gcc/testsuite/g++.dg/cpp0x/alias-decl-27.C
new file mode 100644
index 0000000..91208ab
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/alias-decl-27.C
@@ -0,0 +1,11 @@ 
+// Origin: PR c++/54875
+// { dg-do compile { target c++11 } }
+
+template<typename T>
+using AddConst = T const;
+
+enum FwdEnum : int;
+
+int main() {
+  AddConst<FwdEnum> *ptr = nullptr;
+}