public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH] PR c++/26693
@ 2008-10-29 23:22 Dodji Seketeli
  2008-10-30  0:20 ` Manuel López-Ibáñez
  0 siblings, 1 reply; 17+ messages in thread
From: Dodji Seketeli @ 2008-10-29 23:22 UTC (permalink / raw)
  To: Gcc Patch List; +Cc: Jason Merrill

[-- Attachment #1: Type: text/plain, Size: 516 bytes --]

Hello,

This patch tries to fix PR c++/26693.

Please read the bug analysis in the comments attached to the PR at 
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=26693.

This patch also touches libstdc++ as fixing the PR in g++ revealed a 
typedef name private to a class name being used outside of the class.

If you think I should make a separate patch for libstdc++, please let me 
know.

The patch passes regtest for trunk on x86-64. I am about to try an apply 
  it and regtest it on 4.3 as well.

Thanks.

Dodji.

[-- Attachment #2: PR26693-patch.txt --]
[-- Type: text/plain, Size: 5721 bytes --]

gcc/cp/ChangeLog:
2008-10-29  Dodji Seketeli  <dodji@redhat.com>

	PR c++/26693
	* decl.c (grokdeclarator): when a typedef appears in a
	class, make sure to create the typedef variant type node
	for it. If the typedef'ed struct/class was anonymous, set
	the proper type name to all its type variants.
	* pt.c (tsubst): if we are accessing a type that is a typedef name
	defined in a class, make sure the typedef name is accessible.

gcc/testsuite/ChangeLog:
2008-10-29  Dodji Seketeli  <dodji@redhat.com>

	PR c++/26693
	* g++.dg/template/typedef11.C: New test.

libstdc++-v3/ChangeLog:
@@ -1,3 +1,9 @@
2008-10-29  Dodji Seketeli  <dodji@redhat.com>

	* include/ext/bitmap_allocator.h: the typedefs should be made public
	if we want them to be accessible. This has been revealed by the patch
	that fixes PR c++/26693 in g++.


diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index b0b03a5..cde9241 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -8680,6 +8680,33 @@ grokdeclarator (const cp_declarator *declarator,
 	decl = build_lang_decl (TYPE_DECL, unqualified_id, type);
       else
 	decl = build_decl (TYPE_DECL, unqualified_id, type);
+
+      /* When a typedef statement appears in a class/struct, make sure a
+         'typedef variant type' node is associated to that typedef statement.
+	 This will help to later be able to check the access of the typedef name.
+	 Please read the comment of the function clone_underlying_type in
+	 c-decl.c to learn more about how to represent the type of
+	 a typedef statement.  */
+      if (decl_context == FIELD
+	  && !uses_template_parms (type))
+	{
+	  if (DECL_IS_BUILTIN (decl))
+	    {
+	      if (TYPE_NAME (type) == 0)
+		TYPE_NAME (type) = decl;
+	    }
+	  else
+	    {
+	      DECL_ORIGINAL_TYPE (decl) = type;
+	      type = build_variant_type_copy (type);
+	      TYPE_STUB_DECL (type) = TYPE_STUB_DECL (DECL_ORIGINAL_TYPE (decl));
+	      TYPE_NAME (type) = decl;
+	      TREE_TYPE (decl) = type;
+	    }
+	}
+
+
       if (id_declarator && declarator->u.id.qualifying_scope) {
 	error ("%Jtypedef name may not be a nested-name-specifier", decl);
 	TREE_TYPE (decl) = error_mark_node;
@@ -8714,12 +8741,11 @@ grokdeclarator (const cp_declarator *declarator,
 	  && TYPE_ANONYMOUS_P (type)
 	  && cp_type_quals (type) == TYPE_UNQUALIFIED)
 	{
-	  tree oldname = TYPE_NAME (type);
 	  tree t;
 
 	  /* Replace the anonymous name with the real name everywhere.  */
 	  for (t = TYPE_MAIN_VARIANT (type); t; t = TYPE_NEXT_VARIANT (t))
-	    if (TYPE_NAME (t) == oldname)
+	    if (ANON_AGGRNAME_P (TYPE_IDENTIFIER (t)))
 	      TYPE_NAME (t) = decl;
 
 	  if (TYPE_LANG_SPECIFIC (type))
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 13a2361..75dd215 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -8921,22 +8921,41 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl)
       && TYPE_NAME (t) != TYPE_MAIN_DECL (t))
     {
       tree decl = TYPE_NAME (t);
-      
+
       if (DECL_CLASS_SCOPE_P (decl)
 	  && CLASSTYPE_TEMPLATE_INFO (DECL_CONTEXT (decl))
-	  && uses_template_parms (DECL_CONTEXT (decl)))
+	  && uses_template_parms (DECL_CONTEXT (decl))
+	  && uses_template_parms (decl))
 	{
 	  tree tmpl = most_general_template (DECL_TI_TEMPLATE (decl));
 	  tree gen_args = tsubst (DECL_TI_ARGS (decl), args, complain, in_decl);
 	  r = retrieve_specialization (tmpl, gen_args, false);
+	  if (r && !enforce_access (TYPE_BINFO (DECL_CONTEXT (r)), r, r))
+		return error_mark_node;
 	}
       else if (DECL_FUNCTION_SCOPE_P (decl)
 	       && DECL_TEMPLATE_INFO (DECL_CONTEXT (decl))
 	       && uses_template_parms (DECL_TI_ARGS (DECL_CONTEXT (decl))))
 	r = retrieve_local_specialization (decl);
       else
-	/* The typedef is from a non-template context.  */
-	return t;
+	{
+	  /* The typedef is from a non-template context.  */
+
+	  if (DECL_CONTEXT (decl)
+	      && AGGREGATE_TYPE_P (DECL_CONTEXT (decl))
+	      && !uses_template_parms (DECL_CONTEXT (decl)))
+	    {
+	      /* t has been lowered from a typedef'ed type (namely decl) that is
+		 a member of a class/struct. E.g:
+		 class Foo {
+		  typedef t X;
+		 };
+		 In that example, we need to make sure X is accessible from here.  */
+	      if (!enforce_access (TYPE_BINFO (DECL_CONTEXT (decl)), decl, decl))
+		return error_mark_node;
+	    }
+	  return t;
+	}
 
       if (r)
 	{
diff --git a/gcc/testsuite/g++.dg/template/typedef11.C b/gcc/testsuite/g++.dg/template/typedef11.C
index db7a1d3..6e71729 100644
--- a/gcc/testsuite/g++.dg/template/typedef11.C
+++ b/gcc/testsuite/g++.dg/template/typedef11.C
@@ -2,16 +2,24 @@
 // Origin: PR c++/26693
 // { dg-do compile }
 
-class Foo
+
+class Alpha
+{
+  typedef int X; // { dg-error "'typedef int Alpha::X' is private" }
+};
+
+template<int>
+class Beta
 {
-  typedef int X; // { dg-error "'typedef int Foo::X' is private" }
+    typedef int Y; // { dg-error "'typedef int Beta<0>::Y' is private" }
 };
 
 template <int>
 int
 bar ()
 {
-  return Foo::X (); // { dg-error "within this context" }
+  Beta<0>::Y i = 0; // { dg-error "within this context" }
+  return Alpha::X (); // { dg-error "within this context" }
 }
 
 int i = bar<0> ();
diff --git a/libstdc++-v3/include/ext/bitmap_allocator.h b/libstdc++-v3/include/ext/bitmap_allocator.h
index 7f5466a..7768bd2 100644
--- a/libstdc++-v3/include/ext/bitmap_allocator.h
+++ b/libstdc++-v3/include/ext/bitmap_allocator.h
@@ -549,11 +549,13 @@ _GLIBCXX_BEGIN_NAMESPACE(__gnu_cxx)
    */
   class free_list
   {
+  public:
     typedef size_t* 				value_type;
     typedef __detail::__mini_vector<value_type> vector_type;
     typedef vector_type::iterator 		iterator;
     typedef __mutex				__mutex_type;
 
+  private:
     struct _LT_pointer_compare
     {
       bool

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH] PR c++/26693
  2008-10-29 23:22 [PATCH] PR c++/26693 Dodji Seketeli
@ 2008-10-30  0:20 ` Manuel López-Ibáñez
  2008-10-31  4:12   ` Dodji Seketeli
  0 siblings, 1 reply; 17+ messages in thread
From: Manuel López-Ibáñez @ 2008-10-30  0:20 UTC (permalink / raw)
  To: Dodji Seketeli; +Cc: Gcc Patch List, Jason Merrill

2008/10/29 Dodji Seketeli <dodji@redhat.com>:
> +
> +      /* When a typedef statement appears in a class/struct, make sure a
> +         'typedef variant type' node is associated to that typedef
> statement.
> +        This will help to later be able to check the access of the typedef
> name.
> +        Please read the comment of the function clone_underlying_type in
> +        c-decl.c to learn more about how to represent the type of
> +        a typedef statement.  */
> +      if (decl_context == FIELD
> +         && !uses_template_parms (type))
> +       {
> +         if (DECL_IS_BUILTIN (decl))
> +           {
> +             if (TYPE_NAME (type) == 0)
> +               TYPE_NAME (type) = decl;
> +           }
> +         else
> +           {
> +             DECL_ORIGINAL_TYPE (decl) = type;
> +             type = build_variant_type_copy (type);
> +             TYPE_STUB_DECL (type) = TYPE_STUB_DECL (DECL_ORIGINAL_TYPE
> (decl));
> +             TYPE_NAME (type) = decl;
> +             TREE_TYPE (decl) = type;
> +           }
> +       }
> +
> +

Couldn't you abstract out this code and clone_underlying_type into a
function shared by C/C++? They look almost the same to me. Actually, I
don't understand why c-decl.c does not use TYPE_STUB_DECL.

Moreover, this actually means that we track typedefs, don't we? That
could improve so much our diagnostics in C++!


> @@ -8921,22 +8921,41 @@ tsubst (tree t, tree args, tsubst_flags_t complain,
> tree in_decl)
>       && TYPE_NAME (t) != TYPE_MAIN_DECL (t))
>     {
>       tree decl = TYPE_NAME (t);
> -
> +

Whitespace

> diff --git a/gcc/testsuite/g++.dg/template/typedef11.C
> b/gcc/testsuite/g++.dg/template/typedef11.C
> index db7a1d3..6e71729 100644
> --- a/gcc/testsuite/g++.dg/template/typedef11.C
> +++ b/gcc/testsuite/g++.dg/template/typedef11.C

Is this patch against trunk? I don't see this testcase in FSF's trunk.

Cheers,

Manuel.

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH] PR c++/26693
  2008-10-30  0:20 ` Manuel López-Ibáñez
@ 2008-10-31  4:12   ` Dodji Seketeli
  2008-11-03 18:56     ` Jason Merrill
  0 siblings, 1 reply; 17+ messages in thread
From: Dodji Seketeli @ 2008-10-31  4:12 UTC (permalink / raw)
  To: Manuel López-Ibáñez; +Cc: Gcc Patch List, Jason Merrill

[-- Attachment #1: Type: text/plain, Size: 1528 bytes --]

Manuel López-Ibáñez a écrit :
> 
> Couldn't you abstract out this code and clone_underlying_type into a
> function shared by C/C++? They look almost the same to me.

Yes. I just didn't want to be too disruptive at a first shot. But what 
you say makes sense. In the attached patch, I have moved 
clone_underlying_type to tree.c and I am using it in the c++ front end now.
Also, I have the impression that function name is not really self 
explanatory. Maybe something along the lines of 
setup_type_decl_for_typedef() would be better ?

> Actually, I
> don't understand why c-decl.c does not use TYPE_STUB_DECL.

I am not sure either. It kept clone_underlying_type() as it is though 
for now. I would appreciate if someone could explain why it does not use it.

[...]


>> @@ -8921,22 +8921,41 @@ tsubst (tree t, tree args, tsubst_flags_t complain,
>> tree in_decl)
>>       && TYPE_NAME (t) != TYPE_MAIN_DECL (t))
>>     {
>>       tree decl = TYPE_NAME (t);
>> -
>> +
> 
> Whitespace
>

Oops. I removed that.

>> diff --git a/gcc/testsuite/g++.dg/template/typedef11.C
>> b/gcc/testsuite/g++.dg/template/typedef11.C
>> index db7a1d3..6e71729 100644
>> --- a/gcc/testsuite/g++.dg/template/typedef11.C
>> +++ b/gcc/testsuite/g++.dg/template/typedef11.C
> 
> Is this patch against trunk? I don't see this testcase in FSF's trunk.
> 

Yes. It's me screwing a bit. This is a new test file. The attached path 
makes it clear.

The patch passes regstests on trunk for x86-64.

Thanks.

[-- Attachment #2: PR26693-patch.txt --]
[-- Type: text/plain, Size: 10335 bytes --]

gcc/ChangeLog
2008-10-30  Dodji Seketeli  <dodji@redhat.com>

	* c-decl.c: (clone_underlying_type): Move this  ...
	* tree.c: ... here so that it can be re-used by other front ends.

gcc/cp/ChangeLog:
2008-10-29  Dodji Seketeli  <dodji@redhat.com>

	PR c++/26693
	* decl.c (grokdeclarator): when a typedef appears in a
	class, make sure to create the typedef variant type node
	for it. If the typedef'ed struct/class was anonymous, set
	the proper type name to all its type variants.
	* pt.c (tsubst): if we are accessing a type that is a typedef name
	defined in a class, make sure the typedef name is accessible.

gcc/testsuite/ChangeLog:
2008-10-29  Dodji Seketeli  <dodji@redhat.com>

	PR c++/26693
	* g++.dg/template/typedef11.C: New test.

libstdc++-v3/ChangeLog:
2008-10-29  Dodji Seketeli  <dodji@redhat.com>

	* include/ext/bitmap_allocator.h: the typedefs should be made public
	if we want them to be accessible. This has been revealed by the patch
	that fixes PR c++/26693 in g++.

diff --git a/gcc/c-decl.c b/gcc/c-decl.c
index eba6161..2226928 100644
--- a/gcc/c-decl.c
+++ b/gcc/c-decl.c
@@ -1971,67 +1971,6 @@ warn_if_shadowing (tree new_decl)
       }
 }
 
-
-/* Subroutine of pushdecl.
-
-   X is a TYPE_DECL for a typedef statement.  Create a brand new
-   ..._TYPE node (which will be just a variant of the existing
-   ..._TYPE node with identical properties) and then install X
-   as the TYPE_NAME of this brand new (duplicate) ..._TYPE node.
-
-   The whole point here is to end up with a situation where each
-   and every ..._TYPE node the compiler creates will be uniquely
-   associated with AT MOST one node representing a typedef name.
-   This way, even though the compiler substitutes corresponding
-   ..._TYPE nodes for TYPE_DECL (i.e. "typedef name") nodes very
-   early on, later parts of the compiler can always do the reverse
-   translation and get back the corresponding typedef name.  For
-   example, given:
-
-	typedef struct S MY_TYPE;
-	MY_TYPE object;
-
-   Later parts of the compiler might only know that `object' was of
-   type `struct S' if it were not for code just below.  With this
-   code however, later parts of the compiler see something like:
-
-	struct S' == struct S
-	typedef struct S' MY_TYPE;
-	struct S' object;
-
-    And they can then deduce (from the node for type struct S') that
-    the original object declaration was:
-
-		MY_TYPE object;
-
-    Being able to do this is important for proper support of protoize,
-    and also for generating precise symbolic debugging information
-    which takes full account of the programmer's (typedef) vocabulary.
-
-    Obviously, we don't want to generate a duplicate ..._TYPE node if
-    the TYPE_DECL node that we are now processing really represents a
-    standard built-in type.  */
-
-static void
-clone_underlying_type (tree x)
-{
-  if (DECL_IS_BUILTIN (x))
-    {
-      if (TYPE_NAME (TREE_TYPE (x)) == 0)
-	TYPE_NAME (TREE_TYPE (x)) = x;
-    }
-  else if (TREE_TYPE (x) != error_mark_node
-	   && DECL_ORIGINAL_TYPE (x) == NULL_TREE)
-    {
-      tree tt = TREE_TYPE (x);
-      DECL_ORIGINAL_TYPE (x) = tt;
-      tt = build_variant_type_copy (tt);
-      TYPE_NAME (tt) = x;
-      TREE_USED (tt) = TREE_USED (x);
-      TREE_TYPE (x) = tt;
-    }
-}
-
 /* Record a decl-node X as belonging to the current lexical scope.
    Check for errors (such as an incompatible declaration for the same
    name already seen in the same scope).
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index b0b03a5..8a5d1c3 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -8680,6 +8680,13 @@ grokdeclarator (const cp_declarator *declarator,
 	decl = build_lang_decl (TYPE_DECL, unqualified_id, type);
       else
 	decl = build_decl (TYPE_DECL, unqualified_id, type);
+
+      /* When a typedef statement appears in a class/struct, make sure a
+         'typedef variant type' node is associated to that typedef statement.  */
+      if (decl_context == FIELD
+	  && !uses_template_parms (type))
+	  clone_underlying_type (decl);
+
       if (id_declarator && declarator->u.id.qualifying_scope) {
 	error ("%Jtypedef name may not be a nested-name-specifier", decl);
 	TREE_TYPE (decl) = error_mark_node;
@@ -8714,12 +8721,11 @@ grokdeclarator (const cp_declarator *declarator,
 	  && TYPE_ANONYMOUS_P (type)
 	  && cp_type_quals (type) == TYPE_UNQUALIFIED)
 	{
-	  tree oldname = TYPE_NAME (type);
 	  tree t;
 
 	  /* Replace the anonymous name with the real name everywhere.  */
 	  for (t = TYPE_MAIN_VARIANT (type); t; t = TYPE_NEXT_VARIANT (t))
-	    if (TYPE_NAME (t) == oldname)
+	    if (ANON_AGGRNAME_P (TYPE_IDENTIFIER (t)))
 	      TYPE_NAME (t) = decl;
 
 	  if (TYPE_LANG_SPECIFIC (type))
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 13a2361..c9f5c20 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -8924,19 +8924,38 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl)
       
       if (DECL_CLASS_SCOPE_P (decl)
 	  && CLASSTYPE_TEMPLATE_INFO (DECL_CONTEXT (decl))
-	  && uses_template_parms (DECL_CONTEXT (decl)))
+	  && uses_template_parms (DECL_CONTEXT (decl))
+	  && uses_template_parms (decl))
 	{
 	  tree tmpl = most_general_template (DECL_TI_TEMPLATE (decl));
 	  tree gen_args = tsubst (DECL_TI_ARGS (decl), args, complain, in_decl);
 	  r = retrieve_specialization (tmpl, gen_args, false);
+	  if (r && !enforce_access (TYPE_BINFO (DECL_CONTEXT (r)), r, r))
+		return error_mark_node;
 	}
       else if (DECL_FUNCTION_SCOPE_P (decl)
 	       && DECL_TEMPLATE_INFO (DECL_CONTEXT (decl))
 	       && uses_template_parms (DECL_TI_ARGS (DECL_CONTEXT (decl))))
 	r = retrieve_local_specialization (decl);
       else
-	/* The typedef is from a non-template context.  */
-	return t;
+	{
+	  /* The typedef is from a non-template context.  */
+
+	  if (DECL_CONTEXT (decl)
+	      && AGGREGATE_TYPE_P (DECL_CONTEXT (decl))
+	      && !uses_template_parms (DECL_CONTEXT (decl)))
+	    {
+	      /* t has been lowered from a typedef'ed type (namely decl) that is
+		 a member of a class/struct. E.g:
+		 class Foo {
+		  typedef t X;
+		 };
+		 In that example, we need to make sure X is accessible from here.  */
+	      if (!enforce_access (TYPE_BINFO (DECL_CONTEXT (decl)), decl, decl))
+		return error_mark_node;
+	    }
+	  return t;
+	}
 
       if (r)
 	{
diff --git a/gcc/testsuite/g++.dg/template/typedef11.C b/gcc/testsuite/g++.dg/template/typedef11.C
new file mode 100644
index 0000000..6e71729
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/typedef11.C
@@ -0,0 +1,25 @@
+// Author: Dodji Seketeli <dodji@redhat.com>
+// Origin: PR c++/26693
+// { dg-do compile }
+
+
+class Alpha
+{
+  typedef int X; // { dg-error "'typedef int Alpha::X' is private" }
+};
+
+template<int>
+class Beta
+{
+    typedef int Y; // { dg-error "'typedef int Beta<0>::Y' is private" }
+};
+
+template <int>
+int
+bar ()
+{
+  Beta<0>::Y i = 0; // { dg-error "within this context" }
+  return Alpha::X (); // { dg-error "within this context" }
+}
+
+int i = bar<0> ();
diff --git a/gcc/tree.c b/gcc/tree.c
index 10b50d1..f60818b 100644
--- a/gcc/tree.c
+++ b/gcc/tree.c
@@ -9167,4 +9167,64 @@ build_target_option_node (void)
   return t;
 }
 
+/* Setup a TYPE_DECL node as a typedef representation.
+
+   X is a TYPE_DECL for a typedef statement.  Create a brand new
+   ..._TYPE node (which will be just a variant of the existing
+   ..._TYPE node with identical properties) and then install X
+   as the TYPE_NAME of this brand new (duplicate) ..._TYPE node.
+
+   The whole point here is to end up with a situation where each
+   and every ..._TYPE node the compiler creates will be uniquely
+   associated with AT MOST one node representing a typedef name.
+   This way, even though the compiler substitutes corresponding
+   ..._TYPE nodes for TYPE_DECL (i.e. "typedef name") nodes very
+   early on, later parts of the compiler can always do the reverse
+   translation and get back the corresponding typedef name.  For
+   example, given:
+
+	typedef struct S MY_TYPE;
+	MY_TYPE object;
+
+   Later parts of the compiler might only know that `object' was of
+   type `struct S' if it were not for code just below.  With this
+   code however, later parts of the compiler see something like:
+
+	struct S' == struct S
+	typedef struct S' MY_TYPE;
+	struct S' object;
+
+    And they can then deduce (from the node for type struct S') that
+    the original object declaration was:
+
+		MY_TYPE object;
+
+    Being able to do this is important for proper support of protoize,
+    and also for generating precise symbolic debugging information
+    which takes full account of the programmer's (typedef) vocabulary.
+
+    Obviously, we don't want to generate a duplicate ..._TYPE node if
+    the TYPE_DECL node that we are now processing really represents a
+    standard built-in type.  */
+
+void
+clone_underlying_type (tree x)
+{
+  if (DECL_IS_BUILTIN (x))
+    {
+      if (TYPE_NAME (TREE_TYPE (x)) == 0)
+	TYPE_NAME (TREE_TYPE (x)) = x;
+    }
+  else if (TREE_TYPE (x) != error_mark_node
+	   && DECL_ORIGINAL_TYPE (x) == NULL_TREE)
+    {
+      tree tt = TREE_TYPE (x);
+      DECL_ORIGINAL_TYPE (x) = tt;
+      tt = build_variant_type_copy (tt);
+      TYPE_NAME (tt) = x;
+      TREE_USED (tt) = TREE_USED (x);
+      TREE_TYPE (x) = tt;
+    }
+}
+
 #include "gt-tree.h"
diff --git a/gcc/tree.h b/gcc/tree.h
index a85b4c6..2b3b128 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -3405,6 +3405,8 @@ struct tree_target_option GTY(())
 /* Return a tree node that encapsulates the current target options.  */
 extern tree build_target_option_node (void);
 
+extern void clone_underlying_type (tree x);
+
 \f
 /* Define the overall contents of a tree node.
    It may be any of the structures declared above
diff --git a/libstdc++-v3/include/ext/bitmap_allocator.h b/libstdc++-v3/include/ext/bitmap_allocator.h
index 7f5466a..7768bd2 100644
--- a/libstdc++-v3/include/ext/bitmap_allocator.h
+++ b/libstdc++-v3/include/ext/bitmap_allocator.h
@@ -549,11 +549,13 @@ _GLIBCXX_BEGIN_NAMESPACE(__gnu_cxx)
    */
   class free_list
   {
+  public:
     typedef size_t* 				value_type;
     typedef __detail::__mini_vector<value_type> vector_type;
     typedef vector_type::iterator 		iterator;
     typedef __mutex				__mutex_type;
 
+  private:
     struct _LT_pointer_compare
     {
       bool

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH] PR c++/26693
  2008-10-31  4:12   ` Dodji Seketeli
@ 2008-11-03 18:56     ` Jason Merrill
  2008-11-12 14:49       ` Dodji Seketeli
  0 siblings, 1 reply; 17+ messages in thread
From: Jason Merrill @ 2008-11-03 18:56 UTC (permalink / raw)
  To: Dodji Seketeli; +Cc: Manuel López-Ibáñez, Gcc Patch List

I think putting the code to create typedef variants for class scope 
typedefs belongs in grokfield rather than grokdeclarator.

This patch should also update the code in pushdecl_maybe_friend and 
save_template_attributes that creates typedef variants; the code in 
save_template_attributes may not be necessary anymore, and if it still 
is I'd like to know why.

It also seems that we need clone_underlying_type to propagate 
TYPE_STUB_DECL.

Jason

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH] PR c++/26693
  2008-11-03 18:56     ` Jason Merrill
@ 2008-11-12 14:49       ` Dodji Seketeli
  2008-11-12 21:51         ` Jason Merrill
  0 siblings, 1 reply; 17+ messages in thread
From: Dodji Seketeli @ 2008-11-12 14:49 UTC (permalink / raw)
  To: Jason Merrill; +Cc: Manuel López-Ibáñez, Gcc Patch List

[-- Attachment #1: Type: text/plain, Size: 2354 bytes --]

Hello,

Please find attached a reworked version patch that takes your feedback 
in account. Below are some in-line comments to your precedent email.

Jason Merrill a écrit :
> I think putting the code to create typedef variants for class scope 
> typedefs belongs in grokfield rather than grokdeclarator.

Done.

> This patch should also update the code in pushdecl_maybe_friend and 
> save_template_attributes that creates typedef variants;

Done.

> the code in save_template_attributes may not be necessary anymore, and if it still 
> is I'd like to know why.

Yes, it's not needed anymore.

> It also seems that we need clone_underlying_type to propagate 
> TYPE_STUB_DECL.

Done.

These changes did uncover some additional issues though.
Unlike previously, every class scope typedef is now associated with a 
typedef variant type. This creates some issues when the typedef involves 
typename constructs like: 'typedef typename T::foo bar;'.

The issues are twofold:

1/ If t is a typedef variant type, then TYPE_NAME (t) contains the 
TYPE_DECL representing the declaration of the typedef. But at the same 
time, if t2 is the TYPENAME_TYPE type of 'typename T::foo', then 
TYPE_NAME (t2) will contain the TYPE_DECL representing the declaration 
of 'foo'. So there is a clash regarding the use of TYPE_NAME(t) by 
typedefs and typename constructs. This clash can become pathological 
when we have a construct like 'typedef typename T::foo bar;' that 
involves a typedef and a typename.
So the patch did modify resolve_typename_type() to make it  be aware of 
the issue.

2/ When tsubst() encounters a typedef variant type, it tries to "reuse" 
its specialization, instead of tsubst-ing its main variant type. This 
works great. But when the main variant type is a TYPENAME_TYPE, I think 
we need to make sure the main variant type can be properly tsubst-ed 
before attempting to reuse the specialization of the typedef variant 
type. Otherwise, there are error cases that are not caught and as a 
result g++ would compile things that it should not compile. E.g, g++ 
would fail to report the error on line 14 in 
gcc/testsuite/g++.dg/template/sfinae3.C.
To address this, the patch makes sure the main variant type can be 
tsubst-ed before re-using the typedef variant.

This patch passes regtests and compiles libstdc++ on trunk.

Thanks,

Dodji.

[-- Attachment #2: PR26693-patch-2.txt --]
[-- Type: text/plain, Size: 15295 bytes --]

gcc/ChangeLog:
2008-10-30  Dodji Seketeli  <dodji@redhat.com>

	PR c++/26693
	* c-decl.c: (clone_underlying_type): Move this  ...
	* tree.c: ... here so that it can be re-used by other front ends.
	Also, make sure the function  properly sets TYPE_STUB_DECL() on
	the newly created typedef variant type.

gcc/cp/ChangeLog/
2008-10-29  Dodji Seketeli  <dodji@redhat.com>

	PR c++/26693
	* decl2.c (grokfield): when a typedef appears in a
	class, make sure to create the typedef variant type node
	for it. The creation of the typedef variant is done by calling
	the clone_underlying_type function.
	* name-lookup.c (pushdecl_maybe_friend): Reuse the
	clone_underlying_type function to install typedef variant types.
	* pt.c (tsubst): When faced with the typedef variant type of a
	TYPENAME_TYPE, do not re-use the template specialization of
	the typedef variant type if substituting the corresponding main type variant
	fails.
	If we are accessing a type that is a typedef name defined in a class,
	make sure the typedef name is accessible for it.

gcc/testsuite/ChangeLog:
2008-10-29  Dodji Seketeli  <dodji@redhat.com>

	PR c++/26693
	* g++.dg/template/typedef11.C: New test.

libstdc++-v3/ChangeLog:
2008-10-29  Dodji Seketeli  <dodji@redhat.com>

	* include/ext/bitmap_allocator.h: the typedefs should be made public
	if we want them to be accessible. This has been revealed by the patch
	that fixes PR c++/26693 in g++.

diff --git a/gcc/c-decl.c b/gcc/c-decl.c
index eba6161..2226928 100644
--- a/gcc/c-decl.c
+++ b/gcc/c-decl.c
@@ -1971,67 +1971,6 @@ warn_if_shadowing (tree new_decl)
       }
 }
 
-
-/* Subroutine of pushdecl.
-
-   X is a TYPE_DECL for a typedef statement.  Create a brand new
-   ..._TYPE node (which will be just a variant of the existing
-   ..._TYPE node with identical properties) and then install X
-   as the TYPE_NAME of this brand new (duplicate) ..._TYPE node.
-
-   The whole point here is to end up with a situation where each
-   and every ..._TYPE node the compiler creates will be uniquely
-   associated with AT MOST one node representing a typedef name.
-   This way, even though the compiler substitutes corresponding
-   ..._TYPE nodes for TYPE_DECL (i.e. "typedef name") nodes very
-   early on, later parts of the compiler can always do the reverse
-   translation and get back the corresponding typedef name.  For
-   example, given:
-
-	typedef struct S MY_TYPE;
-	MY_TYPE object;
-
-   Later parts of the compiler might only know that `object' was of
-   type `struct S' if it were not for code just below.  With this
-   code however, later parts of the compiler see something like:
-
-	struct S' == struct S
-	typedef struct S' MY_TYPE;
-	struct S' object;
-
-    And they can then deduce (from the node for type struct S') that
-    the original object declaration was:
-
-		MY_TYPE object;
-
-    Being able to do this is important for proper support of protoize,
-    and also for generating precise symbolic debugging information
-    which takes full account of the programmer's (typedef) vocabulary.
-
-    Obviously, we don't want to generate a duplicate ..._TYPE node if
-    the TYPE_DECL node that we are now processing really represents a
-    standard built-in type.  */
-
-static void
-clone_underlying_type (tree x)
-{
-  if (DECL_IS_BUILTIN (x))
-    {
-      if (TYPE_NAME (TREE_TYPE (x)) == 0)
-	TYPE_NAME (TREE_TYPE (x)) = x;
-    }
-  else if (TREE_TYPE (x) != error_mark_node
-	   && DECL_ORIGINAL_TYPE (x) == NULL_TREE)
-    {
-      tree tt = TREE_TYPE (x);
-      DECL_ORIGINAL_TYPE (x) = tt;
-      tt = build_variant_type_copy (tt);
-      TYPE_NAME (tt) = x;
-      TREE_USED (tt) = TREE_USED (x);
-      TREE_TYPE (x) = tt;
-    }
-}
-
 /* Record a decl-node X as belonging to the current lexical scope.
    Check for errors (such as an incompatible declaration for the same
    name already seen in the same scope).
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index b0b03a5..8ddae96 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -8680,6 +8680,7 @@ grokdeclarator (const cp_declarator *declarator,
 	decl = build_lang_decl (TYPE_DECL, unqualified_id, type);
       else
 	decl = build_decl (TYPE_DECL, unqualified_id, type);
+
       if (id_declarator && declarator->u.id.qualifying_scope) {
 	error ("%Jtypedef name may not be a nested-name-specifier", decl);
 	TREE_TYPE (decl) = error_mark_node;
@@ -8714,12 +8715,11 @@ grokdeclarator (const cp_declarator *declarator,
 	  && TYPE_ANONYMOUS_P (type)
 	  && cp_type_quals (type) == TYPE_UNQUALIFIED)
 	{
-	  tree oldname = TYPE_NAME (type);
 	  tree t;
 
 	  /* Replace the anonymous name with the real name everywhere.  */
 	  for (t = TYPE_MAIN_VARIANT (type); t; t = TYPE_NEXT_VARIANT (t))
-	    if (TYPE_NAME (t) == oldname)
+	    if (ANON_AGGRNAME_P (TYPE_IDENTIFIER (t)))
 	      TYPE_NAME (t) = decl;
 
 	  if (TYPE_LANG_SPECIFIC (type))
diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c
index b326752..17b3460 100644
--- a/gcc/cp/decl2.c
+++ b/gcc/cp/decl2.c
@@ -799,6 +799,9 @@ grokfield (const cp_declarator *declarator,
       DECL_NONLOCAL (value) = 1;
       DECL_CONTEXT (value) = current_class_type;
 
+      if (declspecs->specs[(int)ds_typedef])
+	clone_underlying_type (value);
+
       if (processing_template_decl)
 	value = push_template_decl (value);
 
@@ -1110,19 +1113,6 @@ save_template_attributes (tree *attr_p, tree *decl_p)
   if (!late_attrs)
     return;
 
-  /* Give this type a name so we know to look it up again at instantiation
-     time.  */
-  if (TREE_CODE (*decl_p) == TYPE_DECL
-      && DECL_ORIGINAL_TYPE (*decl_p) == NULL_TREE)
-    {
-      tree oldt = TREE_TYPE (*decl_p);
-      tree newt = build_variant_type_copy (oldt);
-      DECL_ORIGINAL_TYPE (*decl_p) = oldt;
-      TREE_TYPE (*decl_p) = newt;
-      TYPE_NAME (newt) = *decl_p;
-      TREE_USED (newt) = TREE_USED (*decl_p);
-    }
-
   if (DECL_P (*decl_p))
     q = &DECL_ATTRIBUTES (*decl_p);
   else
diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c
index 0da373c..65b9dcd 100644
--- a/gcc/cp/name-lookup.c
+++ b/gcc/cp/name-lookup.c
@@ -847,28 +847,20 @@ pushdecl_maybe_friend (tree x, bool is_friend)
 
       /* If declaring a type as a typedef, copy the type (unless we're
 	 at line 0), and install this TYPE_DECL as the new type's typedef
-	 name.  See the extensive comment in ../c-decl.c (pushdecl).  */
+	 name.  See the extensive comment of clone_underlying_type ().  */
       if (TREE_CODE (x) == TYPE_DECL)
 	{
 	  tree type = TREE_TYPE (x);
-	  if (DECL_IS_BUILTIN (x))
-	    {
-	      if (TYPE_NAME (type) == 0)
-		TYPE_NAME (type) = x;
-	    }
-	  else if (type != error_mark_node && TYPE_NAME (type) != x
-		   /* We don't want to copy the type when all we're
-		      doing is making a TYPE_DECL for the purposes of
-		      inlining.  */
-		   && (!TYPE_NAME (type)
-		       || TYPE_NAME (type) != DECL_ABSTRACT_ORIGIN (x)))
-	    {
-	      DECL_ORIGINAL_TYPE (x) = type;
-	      type = build_variant_type_copy (type);
-	      TYPE_STUB_DECL (type) = TYPE_STUB_DECL (DECL_ORIGINAL_TYPE (x));
-	      TYPE_NAME (type) = x;
-	      TREE_TYPE (x) = type;
-	    }
+
+	  if (DECL_IS_BUILTIN (x)
+	      || (TREE_TYPE (x) != error_mark_node
+		  && TYPE_NAME (type) != x
+		  /* We don't want to copy the type when all we're
+		     doing is making a TYPE_DECL for the purposes of
+		     inlining.  */
+		  && (!TYPE_NAME (type)
+		      || TYPE_NAME (type) != DECL_ABSTRACT_ORIGIN (x))))
+	    clone_underlying_type (x);
 
 	  if (type != error_mark_node
 	      && TYPE_NAME (type)
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 13a2361..a36e951 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -8921,22 +8921,56 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl)
       && TYPE_NAME (t) != TYPE_MAIN_DECL (t))
     {
       tree decl = TYPE_NAME (t);
-      
+
+      if (TREE_CODE (t) == TYPENAME_TYPE)
+	/* Here we are in the case of a declaration that reads:
+	     typedef typename Foo::bar baz;
+	   t is the typedef type variant of the TYPENAME_TYPE type
+	   representing typename Foo::bar.
+	   TYPE_NAME (t) is set to a TYPE_DECL representing the baz typedef.
+	   So before going forward with re-using the baz typedef,
+	   let's see first if tsubst-ing typename Foo::bar leads to an error or not.
+	   If it leads to an error then re-using the baz typedef is wrong. In that
+	   case we shall fall through and let the Foo::bar TYPENAME_TYPE be handled
+	   by the appropriate code that comes later in this function.  */
+	if (tsubst (TREE_TYPE (TYPE_MAIN_DECL (t)), args, tf_none, in_decl)
+	    == error_mark_node)
+	  goto after_typedef_reuse;
+
       if (DECL_CLASS_SCOPE_P (decl)
 	  && CLASSTYPE_TEMPLATE_INFO (DECL_CONTEXT (decl))
-	  && uses_template_parms (DECL_CONTEXT (decl)))
+	  && uses_template_parms (DECL_CONTEXT (decl))
+	  && uses_template_parms (decl))
 	{
 	  tree tmpl = most_general_template (DECL_TI_TEMPLATE (decl));
 	  tree gen_args = tsubst (DECL_TI_ARGS (decl), args, complain, in_decl);
 	  r = retrieve_specialization (tmpl, gen_args, false);
+	  if (r && !enforce_access (TYPE_BINFO (DECL_CONTEXT (r)), r, r))
+		return error_mark_node;
 	}
       else if (DECL_FUNCTION_SCOPE_P (decl)
 	       && DECL_TEMPLATE_INFO (DECL_CONTEXT (decl))
 	       && uses_template_parms (DECL_TI_ARGS (DECL_CONTEXT (decl))))
 	r = retrieve_local_specialization (decl);
       else
-	/* The typedef is from a non-template context.  */
-	return t;
+	{
+	  /* The typedef is from a non-template context.  */
+
+	  if (DECL_CONTEXT (decl)
+	      && AGGREGATE_TYPE_P (DECL_CONTEXT (decl))
+	      && !uses_template_parms (DECL_CONTEXT (decl)))
+	    {
+	      /* t has been lowered from a typedef'ed type (namely decl) that is
+		 a member of a class/struct. E.g:
+		 class Foo {
+		  typedef t X;
+		 };
+		 In that example, we need to make sure X is accessible from here.  */
+	      if (!enforce_access (TYPE_BINFO (DECL_CONTEXT (decl)), decl, decl))
+		return error_mark_node;
+	    }
+	  return t;
+	}
 
       if (r)
 	{
@@ -8948,6 +8982,7 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl)
 	}
       /* Else we must be instantiating the typedef, so fall through.  */
     }
+after_typedef_reuse:
 
   if (type
       && TREE_CODE (t) != TYPENAME_TYPE
@@ -16525,7 +16560,15 @@ resolve_typename_type (tree type, bool only_current_p)
   gcc_assert (TREE_CODE (type) == TYPENAME_TYPE);
 
   scope = TYPE_CONTEXT (type);
-  name = TYPE_IDENTIFIER (type);
+  /* Usually the non-qualified identifier of a TYPENAME_TYPE is
+     TYPE_IDENTIFIER (type). But when 'type' is a typedef variant of
+     a TYPENAME_TYPE node, then TYPE_NAME (type) is set to the TYPE_DECL representing
+     the typedef. In that case TYPE_IDENTIFIER (type) is not the non-qualified
+     identifier  of the TYPENAME_TYPE anymore.
+     So by getting the TYPE_IDENTIFIER of the _main declaration_ of the
+     TYPENAME_TYPE instead, we avoid messing up with a possible
+     typedef variant case.  */
+  name = TYPE_IDENTIFIER (TREE_TYPE (TYPE_MAIN_DECL (type)));
 
   /* If the SCOPE is itself a TYPENAME_TYPE, then we need to resolve
      it first before we can figure out what NAME refers to.  */
diff --git a/gcc/testsuite/g++.dg/template/typedef11.C b/gcc/testsuite/g++.dg/template/typedef11.C
new file mode 100644
index 0000000..6e71729
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/typedef11.C
@@ -0,0 +1,25 @@
+// Author: Dodji Seketeli <dodji@redhat.com>
+// Origin: PR c++/26693
+// { dg-do compile }
+
+
+class Alpha
+{
+  typedef int X; // { dg-error "'typedef int Alpha::X' is private" }
+};
+
+template<int>
+class Beta
+{
+    typedef int Y; // { dg-error "'typedef int Beta<0>::Y' is private" }
+};
+
+template <int>
+int
+bar ()
+{
+  Beta<0>::Y i = 0; // { dg-error "within this context" }
+  return Alpha::X (); // { dg-error "within this context" }
+}
+
+int i = bar<0> ();
diff --git a/gcc/tree.c b/gcc/tree.c
index 10b50d1..4b9e793 100644
--- a/gcc/tree.c
+++ b/gcc/tree.c
@@ -9167,4 +9167,65 @@ build_target_option_node (void)
   return t;
 }
 
+/* Setup a TYPE_DECL node as a typedef representation.
+
+   X is a TYPE_DECL for a typedef statement.  Create a brand new
+   ..._TYPE node (which will be just a variant of the existing
+   ..._TYPE node with identical properties) and then install X
+   as the TYPE_NAME of this brand new (duplicate) ..._TYPE node.
+
+   The whole point here is to end up with a situation where each
+   and every ..._TYPE node the compiler creates will be uniquely
+   associated with AT MOST one node representing a typedef name.
+   This way, even though the compiler substitutes corresponding
+   ..._TYPE nodes for TYPE_DECL (i.e. "typedef name") nodes very
+   early on, later parts of the compiler can always do the reverse
+   translation and get back the corresponding typedef name.  For
+   example, given:
+
+	typedef struct S MY_TYPE;
+	MY_TYPE object;
+
+   Later parts of the compiler might only know that `object' was of
+   type `struct S' if it were not for code just below.  With this
+   code however, later parts of the compiler see something like:
+
+	struct S' == struct S
+	typedef struct S' MY_TYPE;
+	struct S' object;
+
+    And they can then deduce (from the node for type struct S') that
+    the original object declaration was:
+
+		MY_TYPE object;
+
+    Being able to do this is important for proper support of protoize,
+    and also for generating precise symbolic debugging information
+    which takes full account of the programmer's (typedef) vocabulary.
+
+    Obviously, we don't want to generate a duplicate ..._TYPE node if
+    the TYPE_DECL node that we are now processing really represents a
+    standard built-in type.  */
+
+void
+clone_underlying_type (tree x)
+{
+  if (DECL_IS_BUILTIN (x))
+    {
+      if (TYPE_NAME (TREE_TYPE (x)) == 0)
+	TYPE_NAME (TREE_TYPE (x)) = x;
+    }
+  else if (TREE_TYPE (x) != error_mark_node
+	   && DECL_ORIGINAL_TYPE (x) == NULL_TREE)
+    {
+      tree tt = TREE_TYPE (x);
+      DECL_ORIGINAL_TYPE (x) = tt;
+      tt = build_variant_type_copy (tt);
+      TYPE_STUB_DECL (tt) = TYPE_STUB_DECL (DECL_ORIGINAL_TYPE (x));
+      TYPE_NAME (tt) = x;
+      TREE_USED (tt) = TREE_USED (x);
+      TREE_TYPE (x) = tt;
+    }
+}
+
 #include "gt-tree.h"
diff --git a/gcc/tree.h b/gcc/tree.h
index a85b4c6..2b3b128 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -3405,6 +3405,8 @@ struct tree_target_option GTY(())
 /* Return a tree node that encapsulates the current target options.  */
 extern tree build_target_option_node (void);
 
+extern void clone_underlying_type (tree x);
+
 \f
 /* Define the overall contents of a tree node.
    It may be any of the structures declared above
diff --git a/libstdc++-v3/include/ext/bitmap_allocator.h b/libstdc++-v3/include/ext/bitmap_allocator.h
index 7f5466a..7768bd2 100644
--- a/libstdc++-v3/include/ext/bitmap_allocator.h
+++ b/libstdc++-v3/include/ext/bitmap_allocator.h
@@ -549,11 +549,13 @@ _GLIBCXX_BEGIN_NAMESPACE(__gnu_cxx)
    */
   class free_list
   {
+  public:
     typedef size_t* 				value_type;
     typedef __detail::__mini_vector<value_type> vector_type;
     typedef vector_type::iterator 		iterator;
     typedef __mutex				__mutex_type;
 
+  private:
     struct _LT_pointer_compare
     {
       bool

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH] PR c++/26693
  2008-11-12 14:49       ` Dodji Seketeli
@ 2008-11-12 21:51         ` Jason Merrill
  2008-11-13  0:24           ` Dodji Seketeli
  0 siblings, 1 reply; 17+ messages in thread
From: Jason Merrill @ 2008-11-12 21:51 UTC (permalink / raw)
  To: Dodji Seketeli; +Cc: Manuel López-Ibáñez, Gcc Patch List

Dodji Seketeli wrote:
> 2/ When tsubst() encounters a typedef variant type, it tries to "reuse" 
> its specialization, instead of tsubst-ing its main variant type. This 
> works great. But when the main variant type is a TYPENAME_TYPE, I think 
> we need to make sure the main variant type can be properly tsubst-ed 
> before attempting to reuse the specialization of the typedef variant 
> type.

This sounds wrong to me: if tsubsting the TYPENAME_TYPE was going to be 
a problem, we ought to get that error when we instantiate the class of 
which the typedef is a member.

> +	  if (DECL_IS_BUILTIN (x)
> +	      || (TREE_TYPE (x) != error_mark_node
> +		  && TYPE_NAME (type) != x
> +		  /* We don't want to copy the type when all we're
> +		     doing is making a TYPE_DECL for the purposes of
> +		     inlining.  */
> +		  && (!TYPE_NAME (type)
> +		      || TYPE_NAME (type) != DECL_ABSTRACT_ORIGIN (x))))
> +	    clone_underlying_type (x);

This is wrong: if DECL_IS_BUILTIN (x) we don't want to create a typedef 
variant, we just want to set TYPE_NAME (type) to x.

Jason

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH] PR c++/26693
  2008-11-12 21:51         ` Jason Merrill
@ 2008-11-13  0:24           ` Dodji Seketeli
  2008-11-13 20:34             ` Jason Merrill
  0 siblings, 1 reply; 17+ messages in thread
From: Dodji Seketeli @ 2008-11-13  0:24 UTC (permalink / raw)
  To: Jason Merrill; +Cc: Manuel López-Ibáñez, Gcc Patch List

Jason Merrill a écrit :
> Dodji Seketeli wrote:
>> 2/ When tsubst() encounters a typedef variant type, it tries to 
>> "reuse" its specialization, instead of tsubst-ing its main variant 
>> type. This works great. But when the main variant type is a 
>> TYPENAME_TYPE, I think we need to make sure the main variant type can 
>> be properly tsubst-ed before attempting to reuse the specialization of 
>> the typedef variant type.
> 
> This sounds wrong to me: if tsubsting the TYPENAME_TYPE was going to be 
> a problem, we ought to get that error when we instantiate the class of 
> which the typedef is a member.
>

In this code example:
      1  template<typename> struct A
      2  {
      3    typedef int X;
      4    static const int i = 0;
      5  };
      6
      7  template<typename> struct B
      8  {
      9    B(const B&); // { dg-message "candidate" }
     10    typedef typename A<char[A<B>::i]>::X Y;
     11    template<typename T> B(T, Y); // { dg-error "call" }
     12  };
     13
     14  B<int> b(0,0);

There are two sets of error g++ should give us.

The first one is:
: In instantiation of 'B<int>':
:14:   instantiated from here
:10: warning: ISO C++ forbids zero-size array
: In instantiation of 'B<int>':
:14:   instantiated from here

I think it's the one you are talking about. We get that one, even if I 
don't add what I was refering to in the point 2/ of my previous email.

The second set of error g++ should give us is:
:11: error: no matching function for call to 'B<int>::B(int, int)'
:9: note: candidates are: B< <template-parameter-1-1> >::B(const B< 
<template-parameter-1-1> >&) [with <template-parameter-1-1> = int]

This second set of error is missing if I don't handle the particular 
case of typedef variants of TYPENAME_TYPE as was talking about in 2/.

I believe this is one is generated because during instantiation of the 
last parameter (namely the Y typedef) of B<int>::B(int, int), the 
function tsubst() receives a typedef variant of a TYPENAME_TYPE.

Before this patch, the condition:
  if (TYPE_P (t)
       && TYPE_NAME (t)
       && TYPE_NAME (t) != TYPE_MAIN_DECL (t))
     {

was not true, because t was not a typedef variant. So t was handled by 
the TYPENAME_TYPE case that comes later in that function and an error 
was raised.

But after the patch, this condition becomes true and later this if:

     if (DECL_CLASS_SCOPE_P (decl)
         && CLASSTYPE_TEMPLATE_INFO (DECL_CONTEXT (decl))
         && uses_template_parms (DECL_CONTEXT (decl)))
       {
         tree tmpl = most_general_template (DECL_TI_TEMPLATE (decl));
         tree gen_args = tsubst (DECL_TI_ARGS (decl), args, complain, 
in_decl);
         r = retrieve_specialization (tmpl, gen_args, false);
       }

becomes true as well, and later r is returned. This code path doesn't 
raise the error that was raised previously.

So my understanding is the typedef variant of TYPENAME_TYPE triggered a 
different code path that lead to some errors not being raised. I might 
be missing something at this point, but I can't see what :-(.

>> +      if (DECL_IS_BUILTIN (x)
>> +          || (TREE_TYPE (x) != error_mark_node
>> +          && TYPE_NAME (type) != x
>> +          /* We don't want to copy the type when all we're
>> +             doing is making a TYPE_DECL for the purposes of
>> +             inlining.  */
>> +          && (!TYPE_NAME (type)
>> +              || TYPE_NAME (type) != DECL_ABSTRACT_ORIGIN (x))))
>> +        clone_underlying_type (x);
> 
> This is wrong: if DECL_IS_BUILTIN (x) we don't want to create a typedef 
> variant, we just want to set TYPE_NAME (type) to x.
> 

Ah. I did this because clone_underlying_type handles that case of 
DECL_IS_BUILTING (x). I thought duplicating that here would not be 
desirable. So yes, the initial clone_underlying_type does more than just 
creating a typedef variant.

Thanks,

Dodji.

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH] PR c++/26693
  2008-11-13  0:24           ` Dodji Seketeli
@ 2008-11-13 20:34             ` Jason Merrill
  2008-11-17 13:12               ` Dodji Seketeli
  0 siblings, 1 reply; 17+ messages in thread
From: Jason Merrill @ 2008-11-13 20:34 UTC (permalink / raw)
  To: Dodji Seketeli; +Cc: Manuel López-Ibáñez, Gcc Patch List

Dodji Seketeli wrote:
> In this code example:
>      1  template<typename> struct A
>      2  {
>      3    typedef int X;
>      4    static const int i = 0;
>      5  };
>      6
>      7  template<typename> struct B
>      8  {
>      9    B(const B&); // { dg-message "candidate" }
>     10    typedef typename A<char[A<B>::i]>::X Y;
>     11    template<typename T> B(T, Y); // { dg-error "call" }
>     12  };
>     13
>     14  B<int> b(0,0);
[...]
> The second set of error g++ should give us is:
> :11: error: no matching function for call to 'B<int>::B(int, int)'
> :9: note: candidates are: B< <template-parameter-1-1> >::B(const B< 
> <template-parameter-1-1> >&) [with <template-parameter-1-1> = int]
> 
> This second set of error is missing if I don't handle the particular 
> case of typedef variants of TYPENAME_TYPE as was talking about in 2/.
> 
> I believe this is one is generated because during instantiation of the 
> last parameter (namely the Y typedef) of B<int>::B(int, int), the 
> function tsubst() receives a typedef variant of a TYPENAME_TYPE.

Right, because Y is a typedef of a typename type.

> Before this patch, the condition:
>  if (TYPE_P (t)
>       && TYPE_NAME (t)
>       && TYPE_NAME (t) != TYPE_MAIN_DECL (t))
>     {
> 
> was not true, because t was not a typedef variant. So t was handled by 
> the TYPENAME_TYPE case that comes later in that function and an error 
> was raised.
> 
> But after the patch, this condition becomes true and later this if:
> 
>     if (DECL_CLASS_SCOPE_P (decl)
>         && CLASSTYPE_TEMPLATE_INFO (DECL_CONTEXT (decl))
>         && uses_template_parms (DECL_CONTEXT (decl)))
>       {
>         tree tmpl = most_general_template (DECL_TI_TEMPLATE (decl));
>         tree gen_args = tsubst (DECL_TI_ARGS (decl), args, complain, 
> in_decl);
>         r = retrieve_specialization (tmpl, gen_args, false);
>       }
> 
> becomes true as well, and later r is returned.

Yes, that's how I would expect it to work.  The declaration of the 
template constructor uses B<unnamed template parm>::Y, so tsubsting it 
should use B<int>::Y.

> This code path doesn't 
> raise the error that was raised previously.

But that isn't the code path that produces the error.  That error comes 
from the overload resolution code.

> So my understanding is the typedef variant of TYPENAME_TYPE triggered a 
> different code path that lead to some errors not being raised. I might 
> be missing something at this point, but I can't see what :-(.

Here's what's happening: if you use the underlying TYPENAME_TYPE 
directly, you create a zero-length array, which results in a deduction 
failure.  If you use the typedef instead, you get a fully resolved type 
because as an extension G++ allows zero-length arrays outside of the 
argument deduction context.

I think this is the behavior we want; if as an extension we allow B<int> 
to be instantiated at all, we should also allow the use of the Y typedef 
in this situation.  The zero-length array is not coming from argument 
deduction in this case, so it isn't a substitution failure.

Pedantically, the testcase is ill-formed because B<int>::Y is 
ill-formed.  If we allow B<int>::Y, we should also allow it to be used.

>> This is wrong: if DECL_IS_BUILTIN (x) we don't want to create a 
>> typedef variant, we just want to set TYPE_NAME (type) to x.
> 
> Ah. I did this because clone_underlying_type handles that case of 
> DECL_IS_BUILTIN (x).

Ah, I see.

Jason

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH] PR c++/26693
  2008-11-13 20:34             ` Jason Merrill
@ 2008-11-17 13:12               ` Dodji Seketeli
  2008-11-17 17:39                 ` Jason Merrill
  0 siblings, 1 reply; 17+ messages in thread
From: Dodji Seketeli @ 2008-11-17 13:12 UTC (permalink / raw)
  To: Jason Merrill; +Cc: Manuel López-Ibáñez, Gcc Patch List

[-- Attachment #1: Type: text/plain, Size: 816 bytes --]

Jason Merrill a écrit :

[...]

> I think this is the behavior we want; if as an extension we allow B<int> 
> to be instantiated at all, we should also allow the use of the Y typedef 
> in this situation.  The zero-length array is not coming from argument 
> deduction in this case, so it isn't a substitution failure.
> 
> Pedantically, the testcase is ill-formed because B<int>::Y is 
> ill-formed.  If we allow B<int>::Y, we should also allow it to be used.

Okay. So that attached updated patch removes the extra tsubsting of the 
main type variant.
As a result, the patch modifies the two tests that were expecting the 
use the the typedef to be considered erratic. Now only the definition of 
the typedef is considered to be erratic.

The passes passes regtest on trunk for the x86_64 architecture.

Dodji.

[-- Attachment #2: PR26693-patch-3.txt --]
[-- Type: text/plain, Size: 15638 bytes --]

gcc/ChangeLog:
2008-10-30  Dodji Seketeli  <dodji@redhat.com>

	PR c++/26693
	* c-decl.c: (clone_underlying_type): Move this  ...
	* tree.c: ... here so that it can be re-used by other front ends.
	Also, make sure the function  properly sets TYPE_STUB_DECL() on
	the newly created typedef variant type.

gcc/cp/ChangeLog:
2008-10-29  Dodji Seketeli  <dodji@redhat.com>

	PR c++/26693
	* decl2.c (grokfield): when a typedef appears in a
	class, create the typedef variant type node for it.
	* decl.c (grokdeclarator): If the typedef'ed struct/class was
	anonymous, set the proper type name to all its type variants.
	* name-lookup.c (pushdecl_maybe_friend): Reuse the
	clone_underlying_type function to install typedef variant types.
	* pt.c (tsubst): If we are accessing a typdefe'd type defined in a
	class, make sure that typedef is accessible.

gcc/testsuite/ChangeLog:
2008-10-29  Dodji Seketeli  <dodji@redhat.com>

	PR c++/26693
	* g++.dg/template/typedef11.C: New test.
	* g++.dg/template/sfinae3.C: Compile this pedantically.
	The only errors expected should be the one saying the typedef is ill
	formed.
	* g++.old-deja/g++.pt/typename8.C: Likewise.

libstdc++-v3/ChangeLog:
2008-10-29  Dodji Seketeli  <dodji@redhat.com>

	* include/ext/bitmap_allocator.h: the typedefs should be made public
	if we want them to be accessible. This has been revealed by the patch
	that fixes PR c++/26693 in g++.

diff --git a/gcc/c-decl.c b/gcc/c-decl.c
index eba6161..2226928 100644
--- a/gcc/c-decl.c
+++ b/gcc/c-decl.c
@@ -1971,67 +1971,6 @@ warn_if_shadowing (tree new_decl)
       }
 }
 
-
-/* Subroutine of pushdecl.
-
-   X is a TYPE_DECL for a typedef statement.  Create a brand new
-   ..._TYPE node (which will be just a variant of the existing
-   ..._TYPE node with identical properties) and then install X
-   as the TYPE_NAME of this brand new (duplicate) ..._TYPE node.
-
-   The whole point here is to end up with a situation where each
-   and every ..._TYPE node the compiler creates will be uniquely
-   associated with AT MOST one node representing a typedef name.
-   This way, even though the compiler substitutes corresponding
-   ..._TYPE nodes for TYPE_DECL (i.e. "typedef name") nodes very
-   early on, later parts of the compiler can always do the reverse
-   translation and get back the corresponding typedef name.  For
-   example, given:
-
-	typedef struct S MY_TYPE;
-	MY_TYPE object;
-
-   Later parts of the compiler might only know that `object' was of
-   type `struct S' if it were not for code just below.  With this
-   code however, later parts of the compiler see something like:
-
-	struct S' == struct S
-	typedef struct S' MY_TYPE;
-	struct S' object;
-
-    And they can then deduce (from the node for type struct S') that
-    the original object declaration was:
-
-		MY_TYPE object;
-
-    Being able to do this is important for proper support of protoize,
-    and also for generating precise symbolic debugging information
-    which takes full account of the programmer's (typedef) vocabulary.
-
-    Obviously, we don't want to generate a duplicate ..._TYPE node if
-    the TYPE_DECL node that we are now processing really represents a
-    standard built-in type.  */
-
-static void
-clone_underlying_type (tree x)
-{
-  if (DECL_IS_BUILTIN (x))
-    {
-      if (TYPE_NAME (TREE_TYPE (x)) == 0)
-	TYPE_NAME (TREE_TYPE (x)) = x;
-    }
-  else if (TREE_TYPE (x) != error_mark_node
-	   && DECL_ORIGINAL_TYPE (x) == NULL_TREE)
-    {
-      tree tt = TREE_TYPE (x);
-      DECL_ORIGINAL_TYPE (x) = tt;
-      tt = build_variant_type_copy (tt);
-      TYPE_NAME (tt) = x;
-      TREE_USED (tt) = TREE_USED (x);
-      TREE_TYPE (x) = tt;
-    }
-}
-
 /* Record a decl-node X as belonging to the current lexical scope.
    Check for errors (such as an incompatible declaration for the same
    name already seen in the same scope).
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index b0b03a5..8ddae96 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -8680,6 +8680,7 @@ grokdeclarator (const cp_declarator *declarator,
 	decl = build_lang_decl (TYPE_DECL, unqualified_id, type);
       else
 	decl = build_decl (TYPE_DECL, unqualified_id, type);
+
       if (id_declarator && declarator->u.id.qualifying_scope) {
 	error ("%Jtypedef name may not be a nested-name-specifier", decl);
 	TREE_TYPE (decl) = error_mark_node;
@@ -8714,12 +8715,11 @@ grokdeclarator (const cp_declarator *declarator,
 	  && TYPE_ANONYMOUS_P (type)
 	  && cp_type_quals (type) == TYPE_UNQUALIFIED)
 	{
-	  tree oldname = TYPE_NAME (type);
 	  tree t;
 
 	  /* Replace the anonymous name with the real name everywhere.  */
 	  for (t = TYPE_MAIN_VARIANT (type); t; t = TYPE_NEXT_VARIANT (t))
-	    if (TYPE_NAME (t) == oldname)
+	    if (ANON_AGGRNAME_P (TYPE_IDENTIFIER (t)))
 	      TYPE_NAME (t) = decl;
 
 	  if (TYPE_LANG_SPECIFIC (type))
diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c
index b326752..17b3460 100644
--- a/gcc/cp/decl2.c
+++ b/gcc/cp/decl2.c
@@ -799,6 +799,9 @@ grokfield (const cp_declarator *declarator,
       DECL_NONLOCAL (value) = 1;
       DECL_CONTEXT (value) = current_class_type;
 
+      if (declspecs->specs[(int)ds_typedef])
+	clone_underlying_type (value);
+
       if (processing_template_decl)
 	value = push_template_decl (value);
 
@@ -1110,19 +1113,6 @@ save_template_attributes (tree *attr_p, tree *decl_p)
   if (!late_attrs)
     return;
 
-  /* Give this type a name so we know to look it up again at instantiation
-     time.  */
-  if (TREE_CODE (*decl_p) == TYPE_DECL
-      && DECL_ORIGINAL_TYPE (*decl_p) == NULL_TREE)
-    {
-      tree oldt = TREE_TYPE (*decl_p);
-      tree newt = build_variant_type_copy (oldt);
-      DECL_ORIGINAL_TYPE (*decl_p) = oldt;
-      TREE_TYPE (*decl_p) = newt;
-      TYPE_NAME (newt) = *decl_p;
-      TREE_USED (newt) = TREE_USED (*decl_p);
-    }
-
   if (DECL_P (*decl_p))
     q = &DECL_ATTRIBUTES (*decl_p);
   else
diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c
index 0da373c..65b9dcd 100644
--- a/gcc/cp/name-lookup.c
+++ b/gcc/cp/name-lookup.c
@@ -847,28 +847,20 @@ pushdecl_maybe_friend (tree x, bool is_friend)
 
       /* If declaring a type as a typedef, copy the type (unless we're
 	 at line 0), and install this TYPE_DECL as the new type's typedef
-	 name.  See the extensive comment in ../c-decl.c (pushdecl).  */
+	 name.  See the extensive comment of clone_underlying_type ().  */
       if (TREE_CODE (x) == TYPE_DECL)
 	{
 	  tree type = TREE_TYPE (x);
-	  if (DECL_IS_BUILTIN (x))
-	    {
-	      if (TYPE_NAME (type) == 0)
-		TYPE_NAME (type) = x;
-	    }
-	  else if (type != error_mark_node && TYPE_NAME (type) != x
-		   /* We don't want to copy the type when all we're
-		      doing is making a TYPE_DECL for the purposes of
-		      inlining.  */
-		   && (!TYPE_NAME (type)
-		       || TYPE_NAME (type) != DECL_ABSTRACT_ORIGIN (x)))
-	    {
-	      DECL_ORIGINAL_TYPE (x) = type;
-	      type = build_variant_type_copy (type);
-	      TYPE_STUB_DECL (type) = TYPE_STUB_DECL (DECL_ORIGINAL_TYPE (x));
-	      TYPE_NAME (type) = x;
-	      TREE_TYPE (x) = type;
-	    }
+
+	  if (DECL_IS_BUILTIN (x)
+	      || (TREE_TYPE (x) != error_mark_node
+		  && TYPE_NAME (type) != x
+		  /* We don't want to copy the type when all we're
+		     doing is making a TYPE_DECL for the purposes of
+		     inlining.  */
+		  && (!TYPE_NAME (type)
+		      || TYPE_NAME (type) != DECL_ABSTRACT_ORIGIN (x))))
+	    clone_underlying_type (x);
 
 	  if (type != error_mark_node
 	      && TYPE_NAME (type)
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 13a2361..3604801 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -8921,22 +8921,41 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl)
       && TYPE_NAME (t) != TYPE_MAIN_DECL (t))
     {
       tree decl = TYPE_NAME (t);
-      
+
       if (DECL_CLASS_SCOPE_P (decl)
 	  && CLASSTYPE_TEMPLATE_INFO (DECL_CONTEXT (decl))
-	  && uses_template_parms (DECL_CONTEXT (decl)))
+	  && uses_template_parms (DECL_CONTEXT (decl))
+	  && uses_template_parms (decl))
 	{
 	  tree tmpl = most_general_template (DECL_TI_TEMPLATE (decl));
 	  tree gen_args = tsubst (DECL_TI_ARGS (decl), args, complain, in_decl);
 	  r = retrieve_specialization (tmpl, gen_args, false);
+	  if (r && !enforce_access (TYPE_BINFO (DECL_CONTEXT (r)), r, r))
+		return error_mark_node;
 	}
       else if (DECL_FUNCTION_SCOPE_P (decl)
 	       && DECL_TEMPLATE_INFO (DECL_CONTEXT (decl))
 	       && uses_template_parms (DECL_TI_ARGS (DECL_CONTEXT (decl))))
 	r = retrieve_local_specialization (decl);
       else
-	/* The typedef is from a non-template context.  */
-	return t;
+	{
+	  /* The typedef is from a non-template context.  */
+
+	  if (DECL_CONTEXT (decl)
+	      && AGGREGATE_TYPE_P (DECL_CONTEXT (decl))
+	      && !uses_template_parms (DECL_CONTEXT (decl)))
+	    {
+	      /* t has been lowered from a typedef'ed type (namely decl) that is
+		 a member of a class/struct. E.g:
+		 class Foo {
+		  typedef t X;
+		 };
+		 In that example, we need to make sure X is accessible from here.  */
+	      if (!enforce_access (TYPE_BINFO (DECL_CONTEXT (decl)), decl, decl))
+		return error_mark_node;
+	    }
+	  return t;
+	}
 
       if (r)
 	{
@@ -16525,7 +16544,15 @@ resolve_typename_type (tree type, bool only_current_p)
   gcc_assert (TREE_CODE (type) == TYPENAME_TYPE);
 
   scope = TYPE_CONTEXT (type);
-  name = TYPE_IDENTIFIER (type);
+  /* Usually the non-qualified identifier of a TYPENAME_TYPE is
+     TYPE_IDENTIFIER (type). But when 'type' is a typedef variant of
+     a TYPENAME_TYPE node, then TYPE_NAME (type) is set to the TYPE_DECL representing
+     the typedef. In that case TYPE_IDENTIFIER (type) is not the non-qualified
+     identifier  of the TYPENAME_TYPE anymore.
+     So by getting the TYPE_IDENTIFIER of the _main declaration_ of the
+     TYPENAME_TYPE instead, we avoid messing up with a possible
+     typedef variant case.  */
+  name = TYPE_IDENTIFIER (TREE_TYPE (TYPE_MAIN_DECL (type)));
 
   /* If the SCOPE is itself a TYPENAME_TYPE, then we need to resolve
      it first before we can figure out what NAME refers to.  */
diff --git a/gcc/testsuite/g++.dg/template/sfinae3.C b/gcc/testsuite/g++.dg/template/sfinae3.C
index 5799a36..349463d 100644
--- a/gcc/testsuite/g++.dg/template/sfinae3.C
+++ b/gcc/testsuite/g++.dg/template/sfinae3.C
@@ -1,5 +1,5 @@
 // PR c++/24671
-// { dg-options "" }
+// { dg-do compile }
 
 template<typename> struct A
 {
@@ -9,9 +9,9 @@ template<typename> struct A
 
 template<typename> struct B
 {
-  B(const B&); // { dg-message "candidate" }
-  typedef typename A<char[A<B>::i]>::X Y;
-  template<typename T> B(T, Y); // { dg-error "call" }
+  B(const B&);
+  typedef typename A<char[A<B>::i]>::X Y; // { dg-error "forbids zero-size array" }
+  template<typename T> B(T, Y);
 };
 
-B<int> b(0,0); 
+B<int> b(0,0); // { dg-message "instantiated from here" }
diff --git a/gcc/testsuite/g++.dg/template/typedef11.C b/gcc/testsuite/g++.dg/template/typedef11.C
new file mode 100644
index 0000000..6e71729
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/typedef11.C
@@ -0,0 +1,25 @@
+// Author: Dodji Seketeli <dodji@redhat.com>
+// Origin: PR c++/26693
+// { dg-do compile }
+
+
+class Alpha
+{
+  typedef int X; // { dg-error "'typedef int Alpha::X' is private" }
+};
+
+template<int>
+class Beta
+{
+    typedef int Y; // { dg-error "'typedef int Beta<0>::Y' is private" }
+};
+
+template <int>
+int
+bar ()
+{
+  Beta<0>::Y i = 0; // { dg-error "within this context" }
+  return Alpha::X (); // { dg-error "within this context" }
+}
+
+int i = bar<0> ();
diff --git a/gcc/testsuite/g++.old-deja/g++.pt/typename8.C b/gcc/testsuite/g++.old-deja/g++.pt/typename8.C
index 6eb818b..4861cf3 100644
--- a/gcc/testsuite/g++.old-deja/g++.pt/typename8.C
+++ b/gcc/testsuite/g++.old-deja/g++.pt/typename8.C
@@ -5,14 +5,14 @@ template < class T > class A
 public:
   typedef typename T::myT anotherT; // { dg-error "" } undefined type
 
-  anotherT t; // { dg-error "" } undefined type 
+  anotherT t;
 
   A() { }
-  A(anotherT _t) { // { dg-error "" } undefined type
+  A(anotherT _t) {
     t=_t;
   }
 
-  anotherT getT() { // { dg-error "" } undefined type
+  anotherT getT() {
     return t;
   }
 };
diff --git a/gcc/tree.c b/gcc/tree.c
index 10b50d1..4b9e793 100644
--- a/gcc/tree.c
+++ b/gcc/tree.c
@@ -9167,4 +9167,65 @@ build_target_option_node (void)
   return t;
 }
 
+/* Setup a TYPE_DECL node as a typedef representation.
+
+   X is a TYPE_DECL for a typedef statement.  Create a brand new
+   ..._TYPE node (which will be just a variant of the existing
+   ..._TYPE node with identical properties) and then install X
+   as the TYPE_NAME of this brand new (duplicate) ..._TYPE node.
+
+   The whole point here is to end up with a situation where each
+   and every ..._TYPE node the compiler creates will be uniquely
+   associated with AT MOST one node representing a typedef name.
+   This way, even though the compiler substitutes corresponding
+   ..._TYPE nodes for TYPE_DECL (i.e. "typedef name") nodes very
+   early on, later parts of the compiler can always do the reverse
+   translation and get back the corresponding typedef name.  For
+   example, given:
+
+	typedef struct S MY_TYPE;
+	MY_TYPE object;
+
+   Later parts of the compiler might only know that `object' was of
+   type `struct S' if it were not for code just below.  With this
+   code however, later parts of the compiler see something like:
+
+	struct S' == struct S
+	typedef struct S' MY_TYPE;
+	struct S' object;
+
+    And they can then deduce (from the node for type struct S') that
+    the original object declaration was:
+
+		MY_TYPE object;
+
+    Being able to do this is important for proper support of protoize,
+    and also for generating precise symbolic debugging information
+    which takes full account of the programmer's (typedef) vocabulary.
+
+    Obviously, we don't want to generate a duplicate ..._TYPE node if
+    the TYPE_DECL node that we are now processing really represents a
+    standard built-in type.  */
+
+void
+clone_underlying_type (tree x)
+{
+  if (DECL_IS_BUILTIN (x))
+    {
+      if (TYPE_NAME (TREE_TYPE (x)) == 0)
+	TYPE_NAME (TREE_TYPE (x)) = x;
+    }
+  else if (TREE_TYPE (x) != error_mark_node
+	   && DECL_ORIGINAL_TYPE (x) == NULL_TREE)
+    {
+      tree tt = TREE_TYPE (x);
+      DECL_ORIGINAL_TYPE (x) = tt;
+      tt = build_variant_type_copy (tt);
+      TYPE_STUB_DECL (tt) = TYPE_STUB_DECL (DECL_ORIGINAL_TYPE (x));
+      TYPE_NAME (tt) = x;
+      TREE_USED (tt) = TREE_USED (x);
+      TREE_TYPE (x) = tt;
+    }
+}
+
 #include "gt-tree.h"
diff --git a/gcc/tree.h b/gcc/tree.h
index a85b4c6..2b3b128 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -3405,6 +3405,8 @@ struct tree_target_option GTY(())
 /* Return a tree node that encapsulates the current target options.  */
 extern tree build_target_option_node (void);
 
+extern void clone_underlying_type (tree x);
+
 \f
 /* Define the overall contents of a tree node.
    It may be any of the structures declared above
diff --git a/libstdc++-v3/include/ext/bitmap_allocator.h b/libstdc++-v3/include/ext/bitmap_allocator.h
index 7f5466a..7768bd2 100644
--- a/libstdc++-v3/include/ext/bitmap_allocator.h
+++ b/libstdc++-v3/include/ext/bitmap_allocator.h
@@ -549,11 +549,13 @@ _GLIBCXX_BEGIN_NAMESPACE(__gnu_cxx)
    */
   class free_list
   {
+  public:
     typedef size_t* 				value_type;
     typedef __detail::__mini_vector<value_type> vector_type;
     typedef vector_type::iterator 		iterator;
     typedef __mutex				__mutex_type;
 
+  private:
     struct _LT_pointer_compare
     {
       bool

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH] PR c++/26693
  2008-11-17 13:12               ` Dodji Seketeli
@ 2008-11-17 17:39                 ` Jason Merrill
  2008-11-17 22:14                   ` Dodji Seketeli
  0 siblings, 1 reply; 17+ messages in thread
From: Jason Merrill @ 2008-11-17 17:39 UTC (permalink / raw)
  To: Dodji Seketeli; +Cc: Manuel López-Ibáñez, Gcc Patch List

Dodji Seketeli wrote:
> -	  && uses_template_parms (DECL_CONTEXT (decl)))
> +	  && uses_template_parms (DECL_CONTEXT (decl))
> +	  && uses_template_parms (decl))

This seems wrong.  Why wouldn't we want to re-use typedefs with 
non-dependent types?

> +	      if (!enforce_access (TYPE_BINFO (DECL_CONTEXT (decl)), decl, decl))
> +		return error_mark_node;

It occurs to me that just using TYPE_BINFO (DECL_CONTEXT (decl)) may not 
be enough for code that accesses a typedef through a derived class, i.e.

class A
{
  protected:
   typedef int mytype;
};

template <class T> class B;

class C: public A
{
   template <class T> friend class B;
};

template <class T> class B
{
   C::mytype mem;
};

B<int> b;

This is valid, but I believe your patch will cause us to reject it, 
which would be a regression.

> +  name = TYPE_IDENTIFIER (TREE_TYPE (TYPE_MAIN_DECL (type)));

Is this different from TYPE_IDENTIFIER (TYPE_MAIN_VARIANT (type))?

Jason

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH] PR c++/26693
  2008-11-17 17:39                 ` Jason Merrill
@ 2008-11-17 22:14                   ` Dodji Seketeli
  2008-11-18 17:47                     ` Jason Merrill
  0 siblings, 1 reply; 17+ messages in thread
From: Dodji Seketeli @ 2008-11-17 22:14 UTC (permalink / raw)
  To: Jason Merrill; +Cc: Manuel López-Ibáñez, Gcc Patch List

Jason Merrill a écrit :
> Dodji Seketeli wrote:
>> -      && uses_template_parms (DECL_CONTEXT (decl)))
>> +      && uses_template_parms (DECL_CONTEXT (decl))
>> +      && uses_template_parms (decl))
> 
> This seems wrong.  Why wouldn't we want to re-use typedefs with 
> non-dependent types?

Ah, I did this as a stop gap measure because otherwise for a 
non-dependent typedef variant, the compiler was crashing in tree 
gen_args = tsubst (DECL_TI_ARGS (decl), args, complain, in_decl);

I should have investigated. Earlier. Now it seems it is crashing 
eventualy in tsusbt () because of the assert gcc_assert (TREE_VEC_LENGTH 
(args) > 0); around line 9060. This is because we are trying to tsubst a 
  TEMPLATE_PARM_INDEX with a NULL args parameter. I am not sure why the 
assert would be required there. Just handling the arg == NULL case seems 
to fix it.


>> +          if (!enforce_access (TYPE_BINFO (DECL_CONTEXT (decl)), 
>> decl, decl))
>> +        return error_mark_node;
> 
> It occurs to me that just using TYPE_BINFO (DECL_CONTEXT (decl)) may not 
> be enough for code that accesses a typedef through a derived class, i.e.
> 
> class A
> {
>  protected:
>   typedef int mytype;
> };
> 
> template <class T> class B;
> 
> class C: public A
> {
>   template <class T> friend class B;
> };
> 
> template <class T> class B
> {
>   C::mytype mem;
> };
> 
> B<int> b;
> 
> This is valid, but I believe your patch will cause us to reject it, 
> which would be a regression.

Good catch.

Now I guess in this particular case, the right TYPE_BINFO to pass to 
enforce_access() would be the one of the C type, in C::mytype. If that 
is correct then how can I have access to that C type from withing 
tsubst() when I am tsubsting mytype, which TYPE_DECL points to the 
declaration "typedef int mytype;" from class A ? If I can't get that

>> +  name = TYPE_IDENTIFIER (TREE_TYPE (TYPE_MAIN_DECL (type)));
> 
> Is this different from TYPE_IDENTIFIER (TYPE_MAIN_VARIANT (type))?

It seems like both are equal actually.

Dodji.

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH] PR c++/26693
  2008-11-17 22:14                   ` Dodji Seketeli
@ 2008-11-18 17:47                     ` Jason Merrill
  2008-11-30 14:14                       ` Dodji Seketeli
  0 siblings, 1 reply; 17+ messages in thread
From: Jason Merrill @ 2008-11-18 17:47 UTC (permalink / raw)
  To: Dodji Seketeli; +Cc: Manuel López-Ibáñez, Gcc Patch List

Dodji Seketeli wrote:
> Jason Merrill a écrit :
>> Dodji Seketeli wrote:
>>> -      && uses_template_parms (DECL_CONTEXT (decl)))
>>> +      && uses_template_parms (DECL_CONTEXT (decl))
>>> +      && uses_template_parms (decl))
>>
>> This seems wrong.  Why wouldn't we want to re-use typedefs with 
>> non-dependent types?
> 
> Ah, I did this as a stop gap measure because otherwise for a 
> non-dependent typedef variant, the compiler was crashing in tree 
> gen_args = tsubst (DECL_TI_ARGS (decl), args, complain, in_decl);
> 
> I should have investigated. Earlier. Now it seems it is crashing 
> eventualy in tsusbt () because of the assert gcc_assert (TREE_VEC_LENGTH 
> (args) > 0); around line 9060. This is because we are trying to tsubst a 
>  TEMPLATE_PARM_INDEX with a NULL args parameter.

A non-dependent typedef doesn't have the same template args as its 
containing class?  Why isn't the call to push_template_decl from 
grokfield setting that up properly?

>> template <class T> class B
>> {
>>   C::mytype mem;
>> };
> 
> Now I guess in this particular case, the right TYPE_BINFO to pass to 
> enforce_access() would be the one of the C type, in C::mytype. If that 
> is correct then how can I have access to that C type from within 
> tsubst() when I am tsubsting mytype, which TYPE_DECL points to the 
> declaration "typedef int mytype;" from class A ?

The issue is that we need to remember how the name was accessed, not 
just which name was used.  Perhaps using TYPENAME_TYPE to express this 
would work.

Jason

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH] PR c++/26693
  2008-11-18 17:47                     ` Jason Merrill
@ 2008-11-30 14:14                       ` Dodji Seketeli
  2008-12-02 17:06                         ` Jason Merrill
  0 siblings, 1 reply; 17+ messages in thread
From: Dodji Seketeli @ 2008-11-30 14:14 UTC (permalink / raw)
  To: Jason Merrill; +Cc: Gcc Patch List

[-- Attachment #1: Type: text/plain, Size: 2742 bytes --]

Jason Merrill a écrit :
> Dodji Seketeli wrote:
>> Jason Merrill a écrit :
>>> Dodji Seketeli wrote:
>>>> -      && uses_template_parms (DECL_CONTEXT (decl)))
>>>> +      && uses_template_parms (DECL_CONTEXT (decl))
>>>> +      && uses_template_parms (decl))
>>>
>>> This seems wrong.  Why wouldn't we want to re-use typedefs with 
>>> non-dependent types?
>>
>> Ah, I did this as a stop gap measure because otherwise for a 
>> non-dependent typedef variant, the compiler was crashing in tree 
>> gen_args = tsubst (DECL_TI_ARGS (decl), args, complain, in_decl);
>>
>> I should have investigated. Earlier. Now it seems it is crashing 
>> eventualy in tsusbt () because of the assert gcc_assert 
>> (TREE_VEC_LENGTH (args) > 0); around line 9060. This is because we are 
>> trying to tsubst a  TEMPLATE_PARM_INDEX with a NULL args parameter.
> 
> A non-dependent typedef doesn't have the same template args as its 
> containing class?  Why isn't the call to push_template_decl from 
> grokfield setting that up properly?
> 

I think it's because the chain of calls was triggered by a 
fold_non_dependent_expr that calls tsubst_copy_and_build with a NULL 
args argument. I am not sure but I'd say that given that we are calling 
tsubst_copy_and_build with a NULL args, all the tsubst_* routines should 
be able to handle the case of args == NULL somewhat gracefully. 
Shouldn't we ?

The attached patch is an updated version of the earlier one that takes 
the case of a NULL arg in account in tsusbt, for TEMPLATE_PARM_INDEX at 
least. Please tell me if that could be an acceptable approach. I 
consider the patch to be work in progress.

[...]

>> Now I guess in this particular case, the right TYPE_BINFO to pass to 
>> enforce_access() would be the one of the C type, in C::mytype. If that 
>> is correct then how can I have access to that C type from within 
>> tsubst() when I am tsubsting mytype, which TYPE_DECL points to the 
>> declaration "typedef int mytype;" from class A ?
> 
> The issue is that we need to remember how the name was accessed, not 
> just which name was used.  Perhaps using TYPENAME_TYPE to express this 
> would work.

Okay. So as discussed on IRC I tried in the attached patch to store 
typedef types referenced in template code into the template itself, at 
parsing time. Doing it at parsing time allows to also store the scope 
through which the typedef type is accessed.

Later at template instantiation time, the list stored of typedef types 
is walked and each typedef is "access-checked". The access check then 
takes in account the scope through which the typedef is accessed.

The patch applies to trunk, compiles libstdc++ and passes regtests.
Would this approach be worthwhile ?

Thanks,

Dodji.

[-- Attachment #2: PR26693-patch-4.txt --]
[-- Type: text/plain, Size: 25508 bytes --]

gcc/ChangeLog:
2008-11-29  Dodji Seketeli  <dodji@redhat.com>
	PR c++/26693
	* c-decl.c: (clone_underlying_type): Move this  ...
	* tree.c: ... here so that it can be re-used by other front ends.
	Also, make sure the function  properly sets TYPE_STUB_DECL() on
	the newly created typedef variant type.
	(is_typedef_type ): New entry point.
	* tree.h: Added a new member member_types_needing_access_check to
	struct tree_decl_non_common.
	(clone_underlying_type): New entry point.
	(is_typedef_type): Likewise.

gcc/cp/ChangeLog:
2008-11-28  Dodji Seketeli  <dodji@redhat.com>

	PR c++/26693
	* decl2.c (grokfield): when a typedef appears in a
	class, create the typedef variant type node for it.
	* decl.c (grokdeclarator): If the typedef'ed struct/class was
	anonymous, set the proper type name to all its type variants.
	* name-lookup.c (pushdecl_maybe_friend): Reuse the
	clone_underlying_type function to install typedef variant types.
	* cp-tree.h (MEMBER_TYPES_NEEDING_ACCESS_CHECK): New template accessor macro.
	(is_class_nested, append_type_to_template_for_access_check): New
	 entry points.
	* parser.c (cp_parser_nonclass_name): When a typedef that is a member
	of a class appears in a template, add it to the template. It will be
	...
	* pt.c (instantiate_class_template, instantiate_template ): ... access
	checked at template instantiation time.
	(tsubst): There is a FIXME to investigate here ...
	(append_type_to_template_for_access_check): New entry point.
	* search.c (is_class_nested): New entry point.

gcc/testsuite/ChangeLog:
2008-11-29  Dodji Seketeli  <dodji@redhat.com>

	PR c++/26693
	* g++.dg/template/typedef11.C: New test.
	* g++.dg/template/typedef12.C: Likewise.
	* g++.dg/template/typedef13.C: Likewise.
	* g++.dg/template/sfinae3.C: Compile this pedantically.
	The only errors expected should be the one saying the typedef is ill
	formed.
	* g++.old-deja/g++.pt/typename8.C: Likewise.
	* g++.dg/template/access11.C: Update this.

libstdc++-v3/ChangeLog:
2008-11-28  Dodji Seketeli  <dodji@redhat.com>

	* include/ext/bitmap_allocator.h: the typedefs should be made public
	if we want them to be accessible. This has been revealed by the patch
	that fixes PR c++/26693 in g++.

diff --git a/gcc/c-decl.c b/gcc/c-decl.c
index 6f88f62..86ad1a9 100644
--- a/gcc/c-decl.c
+++ b/gcc/c-decl.c
@@ -1971,67 +1971,6 @@ warn_if_shadowing (tree new_decl)
       }
 }
 
-
-/* Subroutine of pushdecl.
-
-   X is a TYPE_DECL for a typedef statement.  Create a brand new
-   ..._TYPE node (which will be just a variant of the existing
-   ..._TYPE node with identical properties) and then install X
-   as the TYPE_NAME of this brand new (duplicate) ..._TYPE node.
-
-   The whole point here is to end up with a situation where each
-   and every ..._TYPE node the compiler creates will be uniquely
-   associated with AT MOST one node representing a typedef name.
-   This way, even though the compiler substitutes corresponding
-   ..._TYPE nodes for TYPE_DECL (i.e. "typedef name") nodes very
-   early on, later parts of the compiler can always do the reverse
-   translation and get back the corresponding typedef name.  For
-   example, given:
-
-	typedef struct S MY_TYPE;
-	MY_TYPE object;
-
-   Later parts of the compiler might only know that `object' was of
-   type `struct S' if it were not for code just below.  With this
-   code however, later parts of the compiler see something like:
-
-	struct S' == struct S
-	typedef struct S' MY_TYPE;
-	struct S' object;
-
-    And they can then deduce (from the node for type struct S') that
-    the original object declaration was:
-
-		MY_TYPE object;
-
-    Being able to do this is important for proper support of protoize,
-    and also for generating precise symbolic debugging information
-    which takes full account of the programmer's (typedef) vocabulary.
-
-    Obviously, we don't want to generate a duplicate ..._TYPE node if
-    the TYPE_DECL node that we are now processing really represents a
-    standard built-in type.  */
-
-static void
-clone_underlying_type (tree x)
-{
-  if (DECL_IS_BUILTIN (x))
-    {
-      if (TYPE_NAME (TREE_TYPE (x)) == 0)
-	TYPE_NAME (TREE_TYPE (x)) = x;
-    }
-  else if (TREE_TYPE (x) != error_mark_node
-	   && DECL_ORIGINAL_TYPE (x) == NULL_TREE)
-    {
-      tree tt = TREE_TYPE (x);
-      DECL_ORIGINAL_TYPE (x) = tt;
-      tt = build_variant_type_copy (tt);
-      TYPE_NAME (tt) = x;
-      TREE_USED (tt) = TREE_USED (x);
-      TREE_TYPE (x) = tt;
-    }
-}
-
 /* Record a decl-node X as belonging to the current lexical scope.
    Check for errors (such as an incompatible declaration for the same
    name already seen in the same scope).
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 9f10ed1..9574f44 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -444,6 +444,15 @@ typedef enum cp_id_kind
 #define IDENTIFIER_REPO_CHOSEN(NAME) \
   (TREE_LANG_FLAG_6 (NAME))
 
+/* The chained list of some types that are referenced in templates.
+   These types are those which need to be access checked at
+   template instantiation time.  For the time being, only typedef-ed types defined
+   as class members are put here at parsing time.
+   Other types for which access check could be required at template instantiation
+   time could be added later.  */
+#define MEMBER_TYPES_NEEDING_ACCESS_CHECK(NODE) \
+  DECL_NON_COMMON_CHECK (NODE)->decl_non_common.member_types_needing_access_check
+
 /* In a RECORD_TYPE or UNION_TYPE, nonzero if any component is read-only.  */
 #define C_TYPE_FIELDS_READONLY(TYPE) \
   (LANG_TYPE_CLASS_CHECK (TYPE)->fields_readonly)
@@ -4231,6 +4240,7 @@ extern void pushclass				(tree);
 extern void popclass				(void);
 extern void push_nested_class			(tree);
 extern void pop_nested_class			(void);
+extern bool is_class_nested			(tree, tree);
 extern int current_lang_depth			(void);
 extern void push_lang_context			(tree);
 extern void pop_lang_context			(void);
@@ -4532,6 +4542,7 @@ extern tree check_explicit_specialization	(tree, tree, int, int);
 extern tree make_auto				(void);
 extern tree do_auto_deduction			(tree, tree, tree);
 extern tree type_uses_auto			(tree);
+extern void append_type_to_template_for_access_check (tree, tree, tree);
 extern tree splice_late_return_type		(tree, tree);
 extern bool is_auto				(const_tree);
 extern tree process_template_parm		(tree, tree, bool, bool);
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 997c580..92df629 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -8725,6 +8725,7 @@ grokdeclarator (const cp_declarator *declarator,
 	decl = build_lang_decl (TYPE_DECL, unqualified_id, type);
       else
 	decl = build_decl (TYPE_DECL, unqualified_id, type);
+
       if (id_declarator && declarator->u.id.qualifying_scope) {
 	error ("%Jtypedef name may not be a nested-name-specifier", decl);
 	TREE_TYPE (decl) = error_mark_node;
@@ -8759,12 +8760,11 @@ grokdeclarator (const cp_declarator *declarator,
 	  && TYPE_ANONYMOUS_P (type)
 	  && cp_type_quals (type) == TYPE_UNQUALIFIED)
 	{
-	  tree oldname = TYPE_NAME (type);
 	  tree t;
 
 	  /* Replace the anonymous name with the real name everywhere.  */
 	  for (t = TYPE_MAIN_VARIANT (type); t; t = TYPE_NEXT_VARIANT (t))
-	    if (TYPE_NAME (t) == oldname)
+	    if (ANON_AGGRNAME_P (TYPE_IDENTIFIER (t)))
 	      TYPE_NAME (t) = decl;
 
 	  if (TYPE_LANG_SPECIFIC (type))
diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c
index da9201e..6f5aa10 100644
--- a/gcc/cp/decl2.c
+++ b/gcc/cp/decl2.c
@@ -804,6 +804,9 @@ grokfield (const cp_declarator *declarator,
       DECL_NONLOCAL (value) = 1;
       DECL_CONTEXT (value) = current_class_type;
 
+      if (declspecs->specs[(int)ds_typedef])
+	clone_underlying_type (value);
+
       if (processing_template_decl)
 	value = push_template_decl (value);
 
@@ -1125,19 +1128,6 @@ save_template_attributes (tree *attr_p, tree *decl_p)
   if (!late_attrs)
     return;
 
-  /* Give this type a name so we know to look it up again at instantiation
-     time.  */
-  if (TREE_CODE (*decl_p) == TYPE_DECL
-      && DECL_ORIGINAL_TYPE (*decl_p) == NULL_TREE)
-    {
-      tree oldt = TREE_TYPE (*decl_p);
-      tree newt = build_variant_type_copy (oldt);
-      DECL_ORIGINAL_TYPE (*decl_p) = oldt;
-      TREE_TYPE (*decl_p) = newt;
-      TYPE_NAME (newt) = *decl_p;
-      TREE_USED (newt) = TREE_USED (*decl_p);
-    }
-
   if (DECL_P (*decl_p))
     q = &DECL_ATTRIBUTES (*decl_p);
   else
diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c
index 0da373c..65b9dcd 100644
--- a/gcc/cp/name-lookup.c
+++ b/gcc/cp/name-lookup.c
@@ -847,28 +847,20 @@ pushdecl_maybe_friend (tree x, bool is_friend)
 
       /* If declaring a type as a typedef, copy the type (unless we're
 	 at line 0), and install this TYPE_DECL as the new type's typedef
-	 name.  See the extensive comment in ../c-decl.c (pushdecl).  */
+	 name.  See the extensive comment of clone_underlying_type ().  */
       if (TREE_CODE (x) == TYPE_DECL)
 	{
 	  tree type = TREE_TYPE (x);
-	  if (DECL_IS_BUILTIN (x))
-	    {
-	      if (TYPE_NAME (type) == 0)
-		TYPE_NAME (type) = x;
-	    }
-	  else if (type != error_mark_node && TYPE_NAME (type) != x
-		   /* We don't want to copy the type when all we're
-		      doing is making a TYPE_DECL for the purposes of
-		      inlining.  */
-		   && (!TYPE_NAME (type)
-		       || TYPE_NAME (type) != DECL_ABSTRACT_ORIGIN (x)))
-	    {
-	      DECL_ORIGINAL_TYPE (x) = type;
-	      type = build_variant_type_copy (type);
-	      TYPE_STUB_DECL (type) = TYPE_STUB_DECL (DECL_ORIGINAL_TYPE (x));
-	      TYPE_NAME (type) = x;
-	      TREE_TYPE (x) = type;
-	    }
+
+	  if (DECL_IS_BUILTIN (x)
+	      || (TREE_TYPE (x) != error_mark_node
+		  && TYPE_NAME (type) != x
+		  /* We don't want to copy the type when all we're
+		     doing is making a TYPE_DECL for the purposes of
+		     inlining.  */
+		  && (!TYPE_NAME (type)
+		      || TYPE_NAME (type) != DECL_ABSTRACT_ORIGIN (x))))
+	    clone_underlying_type (x);
 
 	  if (type != error_mark_node
 	      && TYPE_NAME (type)
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index 8fdd58c..515aeb6 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -11367,7 +11367,39 @@ cp_parser_nonclass_name (cp_parser* parser)
   else if (type_decl != error_mark_node
 	   && !parser->scope)
     maybe_note_name_used_in_class (identifier, type_decl);
-  
+
+  /* If we are parsing a template declaration and if decl is a typedef,
+     add it to a list tied to the template.
+     At template instantiation time, that list will be walked and
+     access check performed.  */
+  {
+    /* This the scope through which type_decl is accessed.
+       It will be useful information later to do access check for
+       type_decl usage.  */
+    tree scope = parser->scope ? parser->scope : DECL_CONTEXT (type_decl);
+    tree templ_info = NULL;
+    tree templ_type = NULL;
+
+    if (current_function_decl)
+      templ_type = current_function_decl;
+    else if (current_class_type)
+      templ_type = current_class_type;
+    if (templ_type)
+      templ_info = get_template_info (templ_type);
+
+    if (templ_info
+	&& TI_TEMPLATE (templ_info)
+	&& is_typedef_type (type_decl)
+	&& scope
+	&& CLASS_TYPE_P (scope)
+	&& ((current_class_type
+	     && !same_type_p (scope, current_class_type)
+	     && !is_class_nested (scope, current_class_type))
+	    || current_function_decl))
+	  append_type_to_template_for_access_check (templ_type,
+						    type_decl,
+						    scope);
+  }
   return type_decl;
 }
 
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 127d37c..37ab921 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -7320,6 +7320,30 @@ instantiate_class_template (tree type)
 	  && DECL_TEMPLATE_INFO (t))
 	tsubst_default_arguments (t);
 
+  /* Some types referenced from within the template code need to be access
+     checked at template instantiation time, i.e now. These types were
+     added to the template at parsing time. Let's get those and perfom
+     the acces checks then.  */
+  for (t = MEMBER_TYPES_NEEDING_ACCESS_CHECK (templ); t; t = TREE_CHAIN (t))
+    {
+      tree type_decl = TREE_PURPOSE (t);
+      tree type_scope = TREE_VALUE (t);
+
+      gcc_assert (type_decl && type_scope);
+
+      if (uses_template_parms (type_decl))
+	type_decl = tsubst (type_decl, args, tf_error, NULL_TREE);
+
+      if (uses_template_parms (type_scope))
+	type_scope = tsubst (type_scope, args, tf_error, NULL_TREE);
+
+      gcc_assert (type_decl && type_decl != error_mark_node
+		  && type_scope && type_scope != error_mark_node);
+
+      perform_or_defer_access_check (TYPE_BINFO (type_scope), type_decl, type_decl);
+    }
+
+  perform_deferred_access_checks ();
   pop_nested_class ();
   pop_from_top_level ();
   pop_deferring_access_checks ();
@@ -8922,12 +8946,15 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl)
       && TYPE_NAME (t) != TYPE_MAIN_DECL (t))
     {
       tree decl = TYPE_NAME (t);
-      
+
       if (DECL_CLASS_SCOPE_P (decl)
 	  && CLASSTYPE_TEMPLATE_INFO (DECL_CONTEXT (decl))
 	  && uses_template_parms (DECL_CONTEXT (decl)))
 	{
 	  tree tmpl = most_general_template (DECL_TI_TEMPLATE (decl));
+	  /* FIXME: investigate why this call crashes for some
+	   * non-dependent typedefs called with NULL args.  This eventually
+	     crashes in tsubst, for the TEMPLATE_PARM_INDEX case.  */
 	  tree gen_args = tsubst (DECL_TI_ARGS (decl), args, complain, in_decl);
 	  r = retrieve_specialization (tmpl, gen_args, false);
 	}
@@ -9039,11 +9066,14 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl)
 
 	r = NULL_TREE;
 
-	gcc_assert (TREE_VEC_LENGTH (args) > 0);
+	/* FIXME: understand why we are hitting this assert.
+	   This comes from when tsubst is called with a non-dependent typedef
+	   with NULL args.  */
+	/*gcc_assert (TREE_VEC_LENGTH (args) > 0);*/
 	template_parm_level_and_index (t, &level, &idx); 
 
 	levels = TMPL_ARGS_DEPTH (args);
-	if (level <= levels)
+	if (args && level <= levels)
 	  {
 	    arg = TMPL_ARG (args, level, idx);
 
@@ -11763,6 +11793,7 @@ instantiate_template (tree tmpl, tree targ_ptr, tsubst_flags_t complain)
   tree fndecl;
   tree gen_tmpl;
   tree spec;
+  tree t;
   HOST_WIDE_INT saved_processing_template_decl;
 
   if (tmpl == error_mark_node)
@@ -11841,6 +11872,23 @@ instantiate_template (tree tmpl, tree targ_ptr, tsubst_flags_t complain)
   /* Now we know the specialization, compute access previously
      deferred.  */
   push_access_scope (fndecl);
+
+  /* Some types referenced from within the template code need to be access
+     checked at template instantiation time, i.e now. These types were
+     added to the template at parsing time. Let's get those and perfom
+     the acces checks then.  */
+  for (t = MEMBER_TYPES_NEEDING_ACCESS_CHECK (tmpl); t; t = TREE_CHAIN (t))
+    {
+      tree type_decl = TREE_PURPOSE (t);
+      tree type_scope = TREE_VALUE (t);
+
+      gcc_assert (type_decl && type_scope);
+
+      if (uses_template_parms (type_decl))
+	type_decl = tsubst (type_decl, targ_ptr, tf_error, NULL_TREE);
+
+      perform_or_defer_access_check (TYPE_BINFO (type_scope), type_decl, type_decl);
+    }
   perform_deferred_access_checks ();
   pop_access_scope (fndecl);
   pop_deferring_access_checks ();
@@ -16527,7 +16575,16 @@ resolve_typename_type (tree type, bool only_current_p)
   gcc_assert (TREE_CODE (type) == TYPENAME_TYPE);
 
   scope = TYPE_CONTEXT (type);
-  name = TYPE_IDENTIFIER (type);
+  /* Usually the non-qualified identifier of a TYPENAME_TYPE is
+     TYPE_IDENTIFIER (type). But when 'type' is a typedef variant of
+     a TYPENAME_TYPE node, then TYPE_NAME (type) is set to the TYPE_DECL representing
+     the typedef. In that case TYPE_IDENTIFIER (type) is not the non-qualified
+     identifier  of the TYPENAME_TYPE anymore.
+     So by getting the TYPE_IDENTIFIER of the _main declaration_ of the
+     TYPENAME_TYPE instead, we avoid messing up with a possible
+     typedef variant case.  */
+  /*name = TYPE_IDENTIFIER (TREE_TYPE (TYPE_MAIN_DECL (type)));*/
+  name = TYPE_IDENTIFIER (TYPE_MAIN_VARIANT (type));
 
   /* If the SCOPE is itself a TYPENAME_TYPE, then we need to resolve
      it first before we can figure out what NAME refers to.  */
@@ -16852,4 +16909,28 @@ type_uses_auto (tree type)
   return NULL_TREE;
 }
 
+/* Append TYPE_DECL to the template TYPE.
+   At TYPE instanciation time, TYPE_DECL will be checked to see
+   if it can be accessed through SCOPE.  */
+void
+append_type_to_template_for_access_check (tree type,
+                                          tree type_decl,
+					  tree scope)
+{
+  tree node, templ;
+
+  gcc_assert (type
+	      && get_template_info (type)
+	      && TI_TEMPLATE (get_template_info (type))
+	      && type_decl
+	      && (TREE_CODE (type_decl) == TYPE_DECL));
+
+  templ = TI_TEMPLATE (get_template_info (type));
+  gcc_assert (templ);
+
+  node = build_tree_list (type_decl, scope);
+  MEMBER_TYPES_NEEDING_ACCESS_CHECK (templ) =
+    chainon (node, MEMBER_TYPES_NEEDING_ACCESS_CHECK (templ));
+}
+
 #include "gt-cp-pt.h"
diff --git a/gcc/cp/search.c b/gcc/cp/search.c
index 7fc040b..1cce251 100644
--- a/gcc/cp/search.c
+++ b/gcc/cp/search.c
@@ -2623,3 +2623,20 @@ original_binfo (tree binfo, tree here)
   return result;
 }
 
+/* Returns true if NESTED is a nested class of BASE, false otherwise.  */
+bool
+is_class_nested (tree base, tree nested)
+{
+  tree t;
+
+  if (!base || !nested
+    || !CLASS_TYPE_P (base)
+    || !CLASS_TYPE_P (nested))
+    return false;
+
+  for (t = TYPE_CONTEXT (nested); t && TYPE_P (t); t = TYPE_CONTEXT (t))
+    if (same_type_p (t, base))
+      return true;
+  return false;
+}
+
diff --git a/gcc/testsuite/g++.dg/template/access11.C b/gcc/testsuite/g++.dg/template/access11.C
index 4c8dce5..38bd515 100644
--- a/gcc/testsuite/g++.dg/template/access11.C
+++ b/gcc/testsuite/g++.dg/template/access11.C
@@ -17,8 +17,8 @@ template <> struct X::Y<int> {
   A::X x;			// { dg-error "this context" }
 };
 
-template <typename T> struct X::Y {
+template <typename T> struct X::Y { // { dg-error "this context" }
   typename T::X x;		// { dg-error "this context" }
 };
 
-template struct X::Y<A>;	// { dg-message "instantiated" }
+template struct X::Y<A>;	// { dg-message "instantiated from here" }
diff --git a/gcc/testsuite/g++.dg/template/sfinae3.C b/gcc/testsuite/g++.dg/template/sfinae3.C
index 5799a36..349463d 100644
--- a/gcc/testsuite/g++.dg/template/sfinae3.C
+++ b/gcc/testsuite/g++.dg/template/sfinae3.C
@@ -1,5 +1,5 @@
 // PR c++/24671
-// { dg-options "" }
+// { dg-do compile }
 
 template<typename> struct A
 {
@@ -9,9 +9,9 @@ template<typename> struct A
 
 template<typename> struct B
 {
-  B(const B&); // { dg-message "candidate" }
-  typedef typename A<char[A<B>::i]>::X Y;
-  template<typename T> B(T, Y); // { dg-error "call" }
+  B(const B&);
+  typedef typename A<char[A<B>::i]>::X Y; // { dg-error "forbids zero-size array" }
+  template<typename T> B(T, Y);
 };
 
-B<int> b(0,0); 
+B<int> b(0,0); // { dg-message "instantiated from here" }
diff --git a/gcc/testsuite/g++.dg/template/typedef11.C b/gcc/testsuite/g++.dg/template/typedef11.C
new file mode 100644
index 0000000..c7c7c98
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/typedef11.C
@@ -0,0 +1,25 @@
+// Author: Dodji Seketeli <dodji@redhat.com>
+// Origin: PR c++/26693
+// { dg-do compile }
+
+
+class Alpha
+{
+  typedef int X; // { dg-error "'typedef int Alpha::X' is private" }
+};
+
+template<int>
+class Beta
+{
+    typedef int Y; // { dg-error "'typedef int Beta<0>::Y' is private" }
+};
+
+template <int>
+int
+bar ()
+{
+  Beta<0>::Y i = 0;
+  return Alpha::X ();
+}
+
+int i = bar<0> (); // { dg-error "within this context" }
diff --git a/gcc/testsuite/g++.dg/template/typedef12.C b/gcc/testsuite/g++.dg/template/typedef12.C
new file mode 100644
index 0000000..3060504
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/typedef12.C
@@ -0,0 +1,23 @@
+// Contributed by Dodji Seketeli <dodji@redhat.com>
+// Origin: Jason Merrill <jason@redhat.com>, PR c++/26693
+// { dg-do compile }
+
+class A
+{
+     protected:
+           typedef int mytype;
+};
+
+template <class T> class B;
+
+class C: public A
+{
+      template <class T> friend class B;
+};
+
+template <class T> class B
+{
+      C::mytype mem;
+};
+
+B<int> b;
diff --git a/gcc/testsuite/g++.dg/template/typedef13.C b/gcc/testsuite/g++.dg/template/typedef13.C
new file mode 100644
index 0000000..aa8bb32
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/typedef13.C
@@ -0,0 +1,16 @@
+// Contributed by Dodji Seketeli <dodji@redhat.com>
+// Origin: PR c++/26693
+// { dg-do compile }
+
+class A
+{
+  typedef int mytype; // { dg-error "typedef int A::mytype' is private" }
+};
+
+template <class T> class B : public A
+{ // { dg-error "within this context"  }
+  mytype mem;
+};
+
+B<int> b; // { dg-message "instantiated from here" }
+
diff --git a/gcc/testsuite/g++.old-deja/g++.pt/typename8.C b/gcc/testsuite/g++.old-deja/g++.pt/typename8.C
index 6eb818b..4861cf3 100644
--- a/gcc/testsuite/g++.old-deja/g++.pt/typename8.C
+++ b/gcc/testsuite/g++.old-deja/g++.pt/typename8.C
@@ -5,14 +5,14 @@ template < class T > class A
 public:
   typedef typename T::myT anotherT; // { dg-error "" } undefined type
 
-  anotherT t; // { dg-error "" } undefined type 
+  anotherT t;
 
   A() { }
-  A(anotherT _t) { // { dg-error "" } undefined type
+  A(anotherT _t) {
     t=_t;
   }
 
-  anotherT getT() { // { dg-error "" } undefined type
+  anotherT getT() {
     return t;
   }
 };
diff --git a/gcc/tree.c b/gcc/tree.c
index e74b779..1a1a13c 100644
--- a/gcc/tree.c
+++ b/gcc/tree.c
@@ -9199,4 +9199,76 @@ build_target_option_node (void)
   return t;
 }
 
+/* Setup a TYPE_DECL node as a typedef representation.
+
+   X is a TYPE_DECL for a typedef statement.  Create a brand new
+   ..._TYPE node (which will be just a variant of the existing
+   ..._TYPE node with identical properties) and then install X
+   as the TYPE_NAME of this brand new (duplicate) ..._TYPE node.
+
+   The whole point here is to end up with a situation where each
+   and every ..._TYPE node the compiler creates will be uniquely
+   associated with AT MOST one node representing a typedef name.
+   This way, even though the compiler substitutes corresponding
+   ..._TYPE nodes for TYPE_DECL (i.e. "typedef name") nodes very
+   early on, later parts of the compiler can always do the reverse
+   translation and get back the corresponding typedef name.  For
+   example, given:
+
+	typedef struct S MY_TYPE;
+	MY_TYPE object;
+
+   Later parts of the compiler might only know that `object' was of
+   type `struct S' if it were not for code just below.  With this
+   code however, later parts of the compiler see something like:
+
+	struct S' == struct S
+	typedef struct S' MY_TYPE;
+	struct S' object;
+
+    And they can then deduce (from the node for type struct S') that
+    the original object declaration was:
+
+		MY_TYPE object;
+
+    Being able to do this is important for proper support of protoize,
+    and also for generating precise symbolic debugging information
+    which takes full account of the programmer's (typedef) vocabulary.
+
+    Obviously, we don't want to generate a duplicate ..._TYPE node if
+    the TYPE_DECL node that we are now processing really represents a
+    standard built-in type.  */
+
+void
+clone_underlying_type (tree x)
+{
+  if (DECL_IS_BUILTIN (x))
+    {
+      if (TYPE_NAME (TREE_TYPE (x)) == 0)
+	TYPE_NAME (TREE_TYPE (x)) = x;
+    }
+  else if (TREE_TYPE (x) != error_mark_node
+	   && DECL_ORIGINAL_TYPE (x) == NULL_TREE)
+    {
+      tree tt = TREE_TYPE (x);
+      DECL_ORIGINAL_TYPE (x) = tt;
+      tt = build_variant_type_copy (tt);
+      TYPE_STUB_DECL (tt) = TYPE_STUB_DECL (DECL_ORIGINAL_TYPE (x));
+      TYPE_NAME (tt) = x;
+      TREE_USED (tt) = TREE_USED (x);
+      TREE_TYPE (x) = tt;
+    }
+}
+
+/* Returns true if X is a typedef type.  */
+bool
+is_typedef_type (tree x)
+{
+  return (x
+	  && TREE_CODE (x) == TYPE_DECL
+	  && TYPE_NAME (TREE_TYPE (x))
+	  && TYPE_NAME (TREE_TYPE (x))
+	    != TYPE_STUB_DECL (TYPE_MAIN_VARIANT (TREE_TYPE (x))));
+}
+
 #include "gt-tree.h"
diff --git a/gcc/tree.h b/gcc/tree.h
index d85918f..7882314 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -3160,6 +3160,8 @@ struct tree_decl_non_common GTY(())
   tree result;
   /* C++ uses this in namespaces.  */
   tree vindex;
+  /* C++ uses this in templates.  */
+  tree member_types_needing_access_check;
 };
 
 /* In FUNCTION_DECL, holds the decl for the return value.  */
@@ -3405,6 +3407,9 @@ struct tree_target_option GTY(())
 /* Return a tree node that encapsulates the current target options.  */
 extern tree build_target_option_node (void);
 
+extern void clone_underlying_type (tree x);
+
+extern bool is_typedef_type (tree x);
 \f
 /* Define the overall contents of a tree node.
    It may be any of the structures declared above
diff --git a/libstdc++-v3/include/ext/bitmap_allocator.h b/libstdc++-v3/include/ext/bitmap_allocator.h
index 7f5466a..7768bd2 100644
--- a/libstdc++-v3/include/ext/bitmap_allocator.h
+++ b/libstdc++-v3/include/ext/bitmap_allocator.h
@@ -549,11 +549,13 @@ _GLIBCXX_BEGIN_NAMESPACE(__gnu_cxx)
    */
   class free_list
   {
+  public:
     typedef size_t* 				value_type;
     typedef __detail::__mini_vector<value_type> vector_type;
     typedef vector_type::iterator 		iterator;
     typedef __mutex				__mutex_type;
 
+  private:
     struct _LT_pointer_compare
     {
       bool

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH] PR c++/26693
  2008-11-30 14:14                       ` Dodji Seketeli
@ 2008-12-02 17:06                         ` Jason Merrill
  2008-12-04  0:18                           ` Dodji Seketeli
  0 siblings, 1 reply; 17+ messages in thread
From: Jason Merrill @ 2008-12-02 17:06 UTC (permalink / raw)
  To: Dodji Seketeli; +Cc: Gcc Patch List

Dodji Seketeli wrote:
> Jason Merrill a écrit :

>> A non-dependent typedef doesn't have the same template args as its 
>> containing class?  Why isn't the call to push_template_decl from 
>> grokfield setting that up properly?
> 
> I think it's because the chain of calls was triggered by a 
> fold_non_dependent_expr that calls tsubst_copy_and_build with a NULL 
> args argument.

Oh I see, the typedef has the right args, we just don't have anything to 
substitute into them.

> I am not sure but I'd say that given that we are calling 
> tsubst_copy_and_build with a NULL args, all the tsubst_* routines should 
> be able to handle the case of args == NULL somewhat gracefully. 
> Shouldn't we ?

Yes, I guess if we call tsubst with NULL args, we should just return t 
since we can't do any substitution.  For the case where we're calling it 
from fold_non_dependent_expr, that's the result we're looking for anyway.

However, it sounds like something's broken if we encounter a 
TEMPLATE_PARM_INDEX in something that we're trying to fold as 
non-dependent.  What's the testcase?

> clone_underlying_type

I still find the use of this for builtins confusing, since we aren't 
doing any cloning in that case.  Maybe change the name to 
set_underlying_type?

Also, better to put this and is_typedef_type in c-common.c rather than 
tree.c; they don't apply to other languages.

> 	* tree.h: Added a new member member_types_needing_access_check to
> 	struct tree_decl_non_common.

No; we shouldn't make most decls larger for the sake of something that's 
local to the C++ front end.  I think you can use a TEMPLATE_DECL's 
DECL_LANG_SPECIFIC(decl).u2.access for this list.

> 	* parser.c (cp_parser_nonclass_name): When a typedef that is a member
> 	of a class appears in a template, add it to the template.

Does this handle typedefs of class type?  The standard says that a 
typedef that names a type is a class-name.

I would expect it to be simpler to handle this as another case in 
perform_or_defer_access_check; i.e. if we're in a template defer by 
adding it to the list of access checks for this template.

> +append_type_to_template_for_access_check (tree type,
> +                                          tree type_decl,
> +					  tree scope)
> +{
> +  tree node, templ;
> +
> +  gcc_assert (type
> +	      && get_template_info (type)
> +	      && TI_TEMPLATE (get_template_info (type))
> +	      && type_decl
> +	      && (TREE_CODE (type_decl) == TYPE_DECL));

Don't we need to do the same thing in function templates?

Jason

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH] PR c++/26693
  2008-12-02 17:06                         ` Jason Merrill
@ 2008-12-04  0:18                           ` Dodji Seketeli
  2008-12-04 14:28                             ` Jason Merrill
  0 siblings, 1 reply; 17+ messages in thread
From: Dodji Seketeli @ 2008-12-04  0:18 UTC (permalink / raw)
  To: Jason Merrill; +Cc: Gcc Patch List

[-- Attachment #1: Type: text/plain, Size: 4163 bytes --]

Hello,

Jason Merrill a écrit :

[...]

> Oh I see, the typedef has the right args, we just don't have anything to 
> substitute into them.
> 
>> I am not sure but I'd say that given that we are calling 
>> tsubst_copy_and_build with a NULL args, all the tsubst_* routines 
>> should be able to handle the case of args == NULL somewhat gracefully. 
>> Shouldn't we ?
> 
> Yes, I guess if we call tsubst with NULL args, we should just return t 
> since we can't do any substitution.  For the case where we're calling it 
> from fold_non_dependent_expr, that's the result we're looking for anyway.
>

Yes, that's what is happening in the attached as I remove the assert and 
instead take the NULL args case in account. We just return t.

> However, it sounds like something's broken if we encounter a 
> TEMPLATE_PARM_INDEX in something that we're trying to fold as 
> non-dependent.  What's the testcase?
> 

The test case in the attached patch, in file 
gcc/testsuite/g++.dg/template/typedef14.C. The assert is hit when 
calling fold_non_dependent_expr on "~static_cast<mytype> (0)", which 
eventually calls tsubst on the mytype typedef.

When we tsubst the mytype typedef, we hit the line:
tree gen_args = tsubst (DECL_TI_ARGS (decl), args, complain, in_decl);

DECL_TI_ARGS (decl) returns a VEC of one TEMPLATE_TYPE_PARM, which is T, 
in the testcase. From there the chain of tsubst-ing goes on, gets 
through tsubst_template_arg, where t is a TEMPLATE_TYPE_PARM, sorry, not 
a TEMPLATE_PARM_INDEX. I said TEMPLATE_PARM_INDEX, but that was not 
correct. It really was a TEMPLATE_TYPE_PARM.

>> clone_underlying_type
> 
> I still find the use of this for builtins confusing, since we aren't 
> doing any cloning in that case.  Maybe change the name to 
> set_underlying_type?

Sure. I did it in the attached patch.

> Also, better to put this and is_typedef_type in c-common.c rather than 
> tree.c; they don't apply to other languages.
>

Done.

>>     * tree.h: Added a new member member_types_needing_access_check to
>>     struct tree_decl_non_common.
> 
> No; we shouldn't make most decls larger for the sake of something that's 
> local to the C++ front end.  I think you can use a TEMPLATE_DECL's 
> DECL_LANG_SPECIFIC(decl).u2.access for this list.

Done.

> 
>>     * parser.c (cp_parser_nonclass_name): When a typedef that is a member
>>     of a class appears in a template, add it to the template.
> 
> Does this handle typedefs of class type?  The standard says that a 
> typedef that names a type is a class-name.
> 
> I would expect it to be simpler to handle this as another case in 
> perform_or_defer_access_check; i.e. if we're in a template defer by 
> adding it to the list of access checks for this template.
>

I changed this to actually put the code to append the type the list of 
access checks for the template into check_accessibility_of_qualified_id, 
  as that function was the one called from cp_parser_lookup_name to 
perform the access check. cp_parser_lookup_name being itself called by
both cp_parser_class_name and cp_parser_nonclass_name.

Also, check_accessibility_of_qualified_id is called with parser->scope 
already, so that makes it easier to just use that parser->scope to store 
it into the list of access checks for the template we are interesting in.

So I guess this should roughly do the same as what you are suggesting 
w.r.t. perform_or_defer_access_check, and should work with typedefs of 
class types.


>> +append_type_to_template_for_access_check (tree type,
>> +                                          tree type_decl,
>> +                      tree scope)
>> +{
>> +  tree node, templ;
>> +
>> +  gcc_assert (type
>> +          && get_template_info (type)
>> +          && TI_TEMPLATE (get_template_info (type))
>> +          && type_decl
>> +          && (TREE_CODE (type_decl) == TYPE_DECL));
> 
> Don't we need to do the same thing in function templates?

I am not sure to understand why this wouldn't work for typedef types 
referenced in function templates. Could you please tell me what I am 
missing ?

FWIW, the patch passes regtests and compiles libstdc++ on trunk for x86_64.

Thanks,

Dodji.

[-- Attachment #2: PR26693-patch-5.txt --]
[-- Type: text/plain, Size: 26657 bytes --]

gcc/ChangeLog:
2008-12-03  Dodji Seketeli  <dodji@redhat.com>

	PR c++/26693
	* c-decl.c: (clone_underlying_type): Move this  ...
	* c-common.c (set_underlying_type): ... here.
	Also, make sure the function  properly sets TYPE_STUB_DECL() on
	the newly created typedef variant type.
	(is_typedef_type ): New entry point.
	* tree.h: Added a new member member_types_needing_access_check to
	struct tree_decl_non_common.
	(set_underlying_type): New entry point.
	(is_typedef_type): Likewise.

gcc/cp/ChangeLog:
2008-12-03  Dodji Seketeli  <dodji@redhat.com>

	PR c++/26693
	* decl2.c (grokfield): when a typedef appears in a
	class, create the typedef variant type node for it.
	* decl.c (grokdeclarator): If the typedef'ed struct/class was
	anonymous, set the proper type name to all its type variants.
	* name-lookup.c (pushdecl_maybe_friend): Reuse the
	set_underlying_type function to install typedef variant types.
	* cp-tree.h (MEMBER_TYPES_NEEDING_ACCESS_CHECK): New template accessor macro.
	(is_class_nested, append_type_to_template_for_access_check): New
	 entry points.
	* semantics.c (check_accessibility_of_qualified_id):
	When a typedef that is a member of a class appears in a template,
	add it to the template. It will be ...
	* pt.c (instantiate_class_template, instantiate_template ): ... access
	checked at template instantiation time.
	(tsubst): There is a FIXME to investigate here ...
	(append_type_to_template_for_access_check): New entry point.
	* search.c (is_class_nested): New entry point.

gcc/testsuite/ChangeLog:
2008-12-03  Dodji Seketeli  <dodji@redhat.com>

	PR c++/26693
	* g++.dg/template/typedef11.C: New test.
	* g++.dg/template/typedef12.C: Likewise.
	* g++.dg/template/typedef13.C: Likewise.
	* g++.dg/template/typedef14.C: Likewise.
	* g++.dg/template/sfinae3.C: Compile this pedantically.
	The only errors expected should be the one saying the typedef is ill
	formed.
	* g++.old-deja/g++.pt/typename8.C: Likewise.
	* g++.dg/template/access11.C: Update this.

libstdc++-v3/ChangeLog:
2008-11-28  Dodji Seketeli  <dodji@redhat.com>

	* include/ext/bitmap_allocator.h: the typedefs should be made public
	if we want them to be accessible. This has been revealed by the patch
	that fixes PR c++/26693 in g++.

diff --git a/gcc/c-common.c b/gcc/c-common.c
index e83b58e..1b605e3 100644
--- a/gcc/c-common.c
+++ b/gcc/c-common.c
@@ -8360,4 +8360,81 @@ warn_for_sign_compare (location_t location,
     }
 }
 
+/* Setup a TYPE_DECL node as a typedef representation.
+
+   X is a TYPE_DECL for a typedef statement.  Create a brand new
+   ..._TYPE node (which will be just a variant of the existing
+   ..._TYPE node with identical properties) and then install X
+   as the TYPE_NAME of this brand new (duplicate) ..._TYPE node.
+
+   The whole point here is to end up with a situation where each
+   and every ..._TYPE node the compiler creates will be uniquely
+   associated with AT MOST one node representing a typedef name.
+   This way, even though the compiler substitutes corresponding
+   ..._TYPE nodes for TYPE_DECL (i.e. "typedef name") nodes very
+   early on, later parts of the compiler can always do the reverse
+   translation and get back the corresponding typedef name.  For
+   example, given:
+
+	typedef struct S MY_TYPE;
+	MY_TYPE object;
+
+   Later parts of the compiler might only know that `object' was of
+   type `struct S' if it were not for code just below.  With this
+   code however, later parts of the compiler see something like:
+
+	struct S' == struct S
+	typedef struct S' MY_TYPE;
+	struct S' object;
+
+    And they can then deduce (from the node for type struct S') that
+    the original object declaration was:
+
+		MY_TYPE object;
+
+    Being able to do this is important for proper support of protoize,
+    and also for generating precise symbolic debugging information
+    which takes full account of the programmer's (typedef) vocabulary.
+
+    Obviously, we don't want to generate a duplicate ..._TYPE node if
+    the TYPE_DECL node that we are now processing really represents a
+    standard built-in type.  */
+
+void
+set_underlying_type (tree x)
+{
+
+  if (DECL_IS_BUILTIN (x))
+    {
+      if (TYPE_NAME (TREE_TYPE (x)) == 0)
+	TYPE_NAME (TREE_TYPE (x)) = x;
+    }
+  else if (TREE_TYPE (x) != error_mark_node
+	   && DECL_ORIGINAL_TYPE (x) == NULL_TREE)
+    {
+      tree tt = TREE_TYPE (x);
+      DECL_ORIGINAL_TYPE (x) = tt;
+      tt = build_variant_type_copy (tt);
+      TYPE_STUB_DECL (tt) = TYPE_STUB_DECL (DECL_ORIGINAL_TYPE (x));
+      TYPE_NAME (tt) = x;
+      TREE_USED (tt) = TREE_USED (x);
+      TREE_TYPE (x) = tt;
+    }
+}
+
+/* Returns true if X is a typedef type.  */
+bool
+is_typedef_type (tree x)
+{
+  return (x
+	  && x != error_mark_node
+	  && TREE_CODE (x) == TYPE_DECL
+	  && TREE_TYPE (x)
+	  && TREE_TYPE (x) != error_mark_node
+	  && TYPE_NAME (TREE_TYPE (x))
+	  && TYPE_MAIN_VARIANT (TREE_TYPE (x))
+	  && TYPE_NAME (TREE_TYPE (x))
+	    != TYPE_STUB_DECL (TYPE_MAIN_VARIANT (TREE_TYPE (x))));
+}
+
 #include "gt-c-common.h"
diff --git a/gcc/c-decl.c b/gcc/c-decl.c
index 6f88f62..3a96195 100644
--- a/gcc/c-decl.c
+++ b/gcc/c-decl.c
@@ -1971,67 +1971,6 @@ warn_if_shadowing (tree new_decl)
       }
 }
 
-
-/* Subroutine of pushdecl.
-
-   X is a TYPE_DECL for a typedef statement.  Create a brand new
-   ..._TYPE node (which will be just a variant of the existing
-   ..._TYPE node with identical properties) and then install X
-   as the TYPE_NAME of this brand new (duplicate) ..._TYPE node.
-
-   The whole point here is to end up with a situation where each
-   and every ..._TYPE node the compiler creates will be uniquely
-   associated with AT MOST one node representing a typedef name.
-   This way, even though the compiler substitutes corresponding
-   ..._TYPE nodes for TYPE_DECL (i.e. "typedef name") nodes very
-   early on, later parts of the compiler can always do the reverse
-   translation and get back the corresponding typedef name.  For
-   example, given:
-
-	typedef struct S MY_TYPE;
-	MY_TYPE object;
-
-   Later parts of the compiler might only know that `object' was of
-   type `struct S' if it were not for code just below.  With this
-   code however, later parts of the compiler see something like:
-
-	struct S' == struct S
-	typedef struct S' MY_TYPE;
-	struct S' object;
-
-    And they can then deduce (from the node for type struct S') that
-    the original object declaration was:
-
-		MY_TYPE object;
-
-    Being able to do this is important for proper support of protoize,
-    and also for generating precise symbolic debugging information
-    which takes full account of the programmer's (typedef) vocabulary.
-
-    Obviously, we don't want to generate a duplicate ..._TYPE node if
-    the TYPE_DECL node that we are now processing really represents a
-    standard built-in type.  */
-
-static void
-clone_underlying_type (tree x)
-{
-  if (DECL_IS_BUILTIN (x))
-    {
-      if (TYPE_NAME (TREE_TYPE (x)) == 0)
-	TYPE_NAME (TREE_TYPE (x)) = x;
-    }
-  else if (TREE_TYPE (x) != error_mark_node
-	   && DECL_ORIGINAL_TYPE (x) == NULL_TREE)
-    {
-      tree tt = TREE_TYPE (x);
-      DECL_ORIGINAL_TYPE (x) = tt;
-      tt = build_variant_type_copy (tt);
-      TYPE_NAME (tt) = x;
-      TREE_USED (tt) = TREE_USED (x);
-      TREE_TYPE (x) = tt;
-    }
-}
-
 /* Record a decl-node X as belonging to the current lexical scope.
    Check for errors (such as an incompatible declaration for the same
    name already seen in the same scope).
@@ -2254,7 +2193,7 @@ pushdecl (tree x)
 
  skip_external_and_shadow_checks:
   if (TREE_CODE (x) == TYPE_DECL)
-    clone_underlying_type (x);
+    set_underlying_type (x);
 
   bind (name, x, scope, /*invisible=*/false, nested);
 
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 9f10ed1..23ef874 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -3178,6 +3178,14 @@ more_aggr_init_expr_args_p (const aggr_init_expr_arg_iterator *iter)
    && TREE_CODE (DECL_TEMPLATE_RESULT (NODE)) == TYPE_DECL \
    && !DECL_TEMPLATE_TEMPLATE_PARM_P (NODE))
 
+/* The chained list of some types that are referenced in templates.
+   These types are those which need to be access checked at
+   template instantiation time.  For the time being, only typedef-ed types defined
+   as class members are put here at parsing time.
+   Other types for which access check could be required at template instantiation
+   time could be added later.  */
+#define MEMBER_TYPES_NEEDING_ACCESS_CHECK(NODE) DECL_ACCESS (NODE)
+
 /* Nonzero if NODE which declares a type.  */
 #define DECL_DECLARES_TYPE_P(NODE) \
   (TREE_CODE (NODE) == TYPE_DECL || DECL_CLASS_TEMPLATE_P (NODE))
@@ -4231,6 +4239,7 @@ extern void pushclass				(tree);
 extern void popclass				(void);
 extern void push_nested_class			(tree);
 extern void pop_nested_class			(void);
+extern bool is_class_nested			(tree, tree);
 extern int current_lang_depth			(void);
 extern void push_lang_context			(tree);
 extern void pop_lang_context			(void);
@@ -4532,6 +4541,7 @@ extern tree check_explicit_specialization	(tree, tree, int, int);
 extern tree make_auto				(void);
 extern tree do_auto_deduction			(tree, tree, tree);
 extern tree type_uses_auto			(tree);
+extern void append_type_to_template_for_access_check (tree, tree, tree);
 extern tree splice_late_return_type		(tree, tree);
 extern bool is_auto				(const_tree);
 extern tree process_template_parm		(tree, tree, bool, bool);
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 997c580..92df629 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -8725,6 +8725,7 @@ grokdeclarator (const cp_declarator *declarator,
 	decl = build_lang_decl (TYPE_DECL, unqualified_id, type);
       else
 	decl = build_decl (TYPE_DECL, unqualified_id, type);
+
       if (id_declarator && declarator->u.id.qualifying_scope) {
 	error ("%Jtypedef name may not be a nested-name-specifier", decl);
 	TREE_TYPE (decl) = error_mark_node;
@@ -8759,12 +8760,11 @@ grokdeclarator (const cp_declarator *declarator,
 	  && TYPE_ANONYMOUS_P (type)
 	  && cp_type_quals (type) == TYPE_UNQUALIFIED)
 	{
-	  tree oldname = TYPE_NAME (type);
 	  tree t;
 
 	  /* Replace the anonymous name with the real name everywhere.  */
 	  for (t = TYPE_MAIN_VARIANT (type); t; t = TYPE_NEXT_VARIANT (t))
-	    if (TYPE_NAME (t) == oldname)
+	    if (ANON_AGGRNAME_P (TYPE_IDENTIFIER (t)))
 	      TYPE_NAME (t) = decl;
 
 	  if (TYPE_LANG_SPECIFIC (type))
diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c
index da9201e..4d92e4b 100644
--- a/gcc/cp/decl2.c
+++ b/gcc/cp/decl2.c
@@ -804,6 +804,9 @@ grokfield (const cp_declarator *declarator,
       DECL_NONLOCAL (value) = 1;
       DECL_CONTEXT (value) = current_class_type;
 
+      if (declspecs->specs[(int)ds_typedef])
+	set_underlying_type (value);
+
       if (processing_template_decl)
 	value = push_template_decl (value);
 
@@ -1125,19 +1128,6 @@ save_template_attributes (tree *attr_p, tree *decl_p)
   if (!late_attrs)
     return;
 
-  /* Give this type a name so we know to look it up again at instantiation
-     time.  */
-  if (TREE_CODE (*decl_p) == TYPE_DECL
-      && DECL_ORIGINAL_TYPE (*decl_p) == NULL_TREE)
-    {
-      tree oldt = TREE_TYPE (*decl_p);
-      tree newt = build_variant_type_copy (oldt);
-      DECL_ORIGINAL_TYPE (*decl_p) = oldt;
-      TREE_TYPE (*decl_p) = newt;
-      TYPE_NAME (newt) = *decl_p;
-      TREE_USED (newt) = TREE_USED (*decl_p);
-    }
-
   if (DECL_P (*decl_p))
     q = &DECL_ATTRIBUTES (*decl_p);
   else
diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c
index 0da373c..d9ea96d 100644
--- a/gcc/cp/name-lookup.c
+++ b/gcc/cp/name-lookup.c
@@ -847,28 +847,20 @@ pushdecl_maybe_friend (tree x, bool is_friend)
 
       /* If declaring a type as a typedef, copy the type (unless we're
 	 at line 0), and install this TYPE_DECL as the new type's typedef
-	 name.  See the extensive comment in ../c-decl.c (pushdecl).  */
+	 name.  See the extensive comment of set_underlying_type ().  */
       if (TREE_CODE (x) == TYPE_DECL)
 	{
 	  tree type = TREE_TYPE (x);
-	  if (DECL_IS_BUILTIN (x))
-	    {
-	      if (TYPE_NAME (type) == 0)
-		TYPE_NAME (type) = x;
-	    }
-	  else if (type != error_mark_node && TYPE_NAME (type) != x
-		   /* We don't want to copy the type when all we're
-		      doing is making a TYPE_DECL for the purposes of
-		      inlining.  */
-		   && (!TYPE_NAME (type)
-		       || TYPE_NAME (type) != DECL_ABSTRACT_ORIGIN (x)))
-	    {
-	      DECL_ORIGINAL_TYPE (x) = type;
-	      type = build_variant_type_copy (type);
-	      TYPE_STUB_DECL (type) = TYPE_STUB_DECL (DECL_ORIGINAL_TYPE (x));
-	      TYPE_NAME (type) = x;
-	      TREE_TYPE (x) = type;
-	    }
+
+	  if (DECL_IS_BUILTIN (x)
+	      || (TREE_TYPE (x) != error_mark_node
+		  && TYPE_NAME (type) != x
+		  /* We don't want to copy the type when all we're
+		     doing is making a TYPE_DECL for the purposes of
+		     inlining.  */
+		  && (!TYPE_NAME (type)
+		      || TYPE_NAME (type) != DECL_ABSTRACT_ORIGIN (x))))
+	    set_underlying_type (x);
 
 	  if (type != error_mark_node
 	      && TYPE_NAME (type)
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index 8fdd58c..aa2fad5 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -11367,7 +11367,7 @@ cp_parser_nonclass_name (cp_parser* parser)
   else if (type_decl != error_mark_node
 	   && !parser->scope)
     maybe_note_name_used_in_class (identifier, type_decl);
-  
+
   return type_decl;
 }
 
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 127d37c..fd8b4be 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -7320,6 +7320,31 @@ instantiate_class_template (tree type)
 	  && DECL_TEMPLATE_INFO (t))
 	tsubst_default_arguments (t);
 
+  /* Some types referenced from within the template code need to be access
+     checked at template instantiation time, i.e now. These types were
+     added to the template at parsing time. Let's get those and perfom
+     the acces checks then.  */
+  for (t = MEMBER_TYPES_NEEDING_ACCESS_CHECK (templ); t; t = TREE_CHAIN (t))
+    {
+      tree type_decl = TREE_PURPOSE (t);
+      tree type_scope = TREE_VALUE (t);
+
+      if (!type_decl || !type_scope || !CLASS_TYPE_P (type_scope))
+	continue;
+
+      if (uses_template_parms (type_decl))
+	type_decl = tsubst (type_decl, args, tf_error, NULL_TREE);
+
+      if (uses_template_parms (type_scope))
+	type_scope = tsubst (type_scope, args, tf_error, NULL_TREE);
+
+      gcc_assert (type_decl && type_decl != error_mark_node
+		  && type_scope && type_scope != error_mark_node);
+
+      perform_or_defer_access_check (TYPE_BINFO (type_scope), type_decl, type_decl);
+    }
+
+  perform_deferred_access_checks ();
   pop_nested_class ();
   pop_from_top_level ();
   pop_deferring_access_checks ();
@@ -8922,7 +8947,7 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl)
       && TYPE_NAME (t) != TYPE_MAIN_DECL (t))
     {
       tree decl = TYPE_NAME (t);
-      
+
       if (DECL_CLASS_SCOPE_P (decl)
 	  && CLASSTYPE_TEMPLATE_INFO (DECL_CONTEXT (decl))
 	  && uses_template_parms (DECL_CONTEXT (decl)))
@@ -9039,11 +9064,14 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl)
 
 	r = NULL_TREE;
 
-	gcc_assert (TREE_VEC_LENGTH (args) > 0);
+	/* FIXME: understand why we are hitting this assert.
+	   This comes from when tsubst is called with a non-dependent typedef
+	   with NULL args.  */
+	/*gcc_assert (TREE_VEC_LENGTH (args) > 0);*/
 	template_parm_level_and_index (t, &level, &idx); 
 
 	levels = TMPL_ARGS_DEPTH (args);
-	if (level <= levels)
+	if (args && level <= levels)
 	  {
 	    arg = TMPL_ARG (args, level, idx);
 
@@ -11763,6 +11791,7 @@ instantiate_template (tree tmpl, tree targ_ptr, tsubst_flags_t complain)
   tree fndecl;
   tree gen_tmpl;
   tree spec;
+  tree t;
   HOST_WIDE_INT saved_processing_template_decl;
 
   if (tmpl == error_mark_node)
@@ -11841,6 +11870,24 @@ instantiate_template (tree tmpl, tree targ_ptr, tsubst_flags_t complain)
   /* Now we know the specialization, compute access previously
      deferred.  */
   push_access_scope (fndecl);
+
+  /* Some types referenced from within the template code need to be access
+     checked at template instantiation time, i.e now. These types were
+     added to the template at parsing time. Let's get those and perfom
+     the acces checks then.  */
+  for (t = MEMBER_TYPES_NEEDING_ACCESS_CHECK (tmpl); t; t = TREE_CHAIN (t))
+    {
+      tree type_decl = TREE_PURPOSE (t);
+      tree type_scope = TREE_VALUE (t);
+
+      if (!type_decl || !type_scope || !CLASS_TYPE_P (type_scope))
+	continue;
+
+      if (uses_template_parms (type_decl))
+	type_decl = tsubst (type_decl, targ_ptr, tf_error, NULL_TREE);
+
+      perform_or_defer_access_check (TYPE_BINFO (type_scope), type_decl, type_decl);
+    }
   perform_deferred_access_checks ();
   pop_access_scope (fndecl);
   pop_deferring_access_checks ();
@@ -16527,7 +16574,16 @@ resolve_typename_type (tree type, bool only_current_p)
   gcc_assert (TREE_CODE (type) == TYPENAME_TYPE);
 
   scope = TYPE_CONTEXT (type);
-  name = TYPE_IDENTIFIER (type);
+  /* Usually the non-qualified identifier of a TYPENAME_TYPE is
+     TYPE_IDENTIFIER (type). But when 'type' is a typedef variant of
+     a TYPENAME_TYPE node, then TYPE_NAME (type) is set to the TYPE_DECL representing
+     the typedef. In that case TYPE_IDENTIFIER (type) is not the non-qualified
+     identifier  of the TYPENAME_TYPE anymore.
+     So by getting the TYPE_IDENTIFIER of the _main declaration_ of the
+     TYPENAME_TYPE instead, we avoid messing up with a possible
+     typedef variant case.  */
+  /*name = TYPE_IDENTIFIER (TREE_TYPE (TYPE_MAIN_DECL (type)));*/
+  name = TYPE_IDENTIFIER (TYPE_MAIN_VARIANT (type));
 
   /* If the SCOPE is itself a TYPENAME_TYPE, then we need to resolve
      it first before we can figure out what NAME refers to.  */
@@ -16852,4 +16908,43 @@ type_uses_auto (tree type)
   return NULL_TREE;
 }
 
+/* Append TYPE_DECL to the template TYPE.
+   At TYPE instanciation time, TYPE_DECL will be checked to see
+   if it can be accessed through SCOPE.  */
+void
+append_type_to_template_for_access_check (tree type,
+                                          tree type_decl,
+					  tree scope)
+{
+  tree node, templ;
+
+  gcc_assert (type
+	      && get_template_info (type)
+	      && TI_TEMPLATE (get_template_info (type))
+	      && type_decl
+	      && (TREE_CODE (type_decl) == TYPE_DECL));
+
+  templ = TI_TEMPLATE (get_template_info (type));
+  gcc_assert (templ);
+
+  /* Make sure we don't append the type to the template twice.
+     If this appears to be too slow, the
+     MEMBER_TYPE_NEEDING_ACCESS_CHECK property
+     of templ should be a hash table instead.  */
+  for (node = MEMBER_TYPES_NEEDING_ACCESS_CHECK (templ);
+       node;
+       node = TREE_CHAIN (node))
+    {
+      tree decl = TREE_PURPOSE (node);
+      tree type_scope = TREE_VALUE (node);
+
+      if (decl == type_decl && type_scope == scope)
+	return;
+    }
+
+  node = build_tree_list (type_decl, scope);
+  MEMBER_TYPES_NEEDING_ACCESS_CHECK (templ) =
+    chainon (node, MEMBER_TYPES_NEEDING_ACCESS_CHECK (templ));
+}
+
 #include "gt-cp-pt.h"
diff --git a/gcc/cp/search.c b/gcc/cp/search.c
index 7fc040b..1cce251 100644
--- a/gcc/cp/search.c
+++ b/gcc/cp/search.c
@@ -2623,3 +2623,20 @@ original_binfo (tree binfo, tree here)
   return result;
 }
 
+/* Returns true if NESTED is a nested class of BASE, false otherwise.  */
+bool
+is_class_nested (tree base, tree nested)
+{
+  tree t;
+
+  if (!base || !nested
+    || !CLASS_TYPE_P (base)
+    || !CLASS_TYPE_P (nested))
+    return false;
+
+  for (t = TYPE_CONTEXT (nested); t && TYPE_P (t); t = TYPE_CONTEXT (t))
+    if (same_type_p (t, base))
+      return true;
+  return false;
+}
+
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index e0ae6ff..5ed41c1 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -1524,6 +1524,38 @@ check_accessibility_of_qualified_id (tree decl,
   tree scope;
   tree qualifying_type = NULL_TREE;
 
+  /* If we are parsing a template declaration and if decl is a typedef,
+     add it to a list tied to the template.
+     At template instantiation time, that list will be walked and
+     access check performed.  */
+  if (is_typedef_type (decl))
+    {
+      /* This the scope through which type_decl is accessed.
+	 It will be useful information later to do access check for
+	 type_decl usage.  */
+      tree scope = nested_name_specifier ? nested_name_specifier : DECL_CONTEXT (decl);
+      tree templ_info = NULL;
+      tree templ_type = NULL;
+
+      if (current_function_decl)
+	templ_type = current_function_decl;
+      else if (current_class_type)
+	templ_type = current_class_type;
+      if (templ_type)
+	templ_info = get_template_info (templ_type);
+
+      if (templ_info
+	  && TI_TEMPLATE (templ_info)
+	  && scope
+	  && CLASS_TYPE_P (scope)
+	  && ((current_class_type
+	       && !same_type_p (scope, current_class_type)
+	       && !is_class_nested (scope, current_class_type))
+	      || (current_function_decl
+		  && !DECL_FUNCTION_MEMBER_P (current_function_decl))))
+	append_type_to_template_for_access_check (templ_type, decl, scope);
+    }
+
   /* If we're not checking, return immediately.  */
   if (deferred_access_no_check)
     return;
diff --git a/gcc/testsuite/g++.dg/template/access11.C b/gcc/testsuite/g++.dg/template/access11.C
index 4c8dce5..38bd515 100644
--- a/gcc/testsuite/g++.dg/template/access11.C
+++ b/gcc/testsuite/g++.dg/template/access11.C
@@ -17,8 +17,8 @@ template <> struct X::Y<int> {
   A::X x;			// { dg-error "this context" }
 };
 
-template <typename T> struct X::Y {
+template <typename T> struct X::Y { // { dg-error "this context" }
   typename T::X x;		// { dg-error "this context" }
 };
 
-template struct X::Y<A>;	// { dg-message "instantiated" }
+template struct X::Y<A>;	// { dg-message "instantiated from here" }
diff --git a/gcc/testsuite/g++.dg/template/sfinae3.C b/gcc/testsuite/g++.dg/template/sfinae3.C
index 5799a36..349463d 100644
--- a/gcc/testsuite/g++.dg/template/sfinae3.C
+++ b/gcc/testsuite/g++.dg/template/sfinae3.C
@@ -1,5 +1,5 @@
 // PR c++/24671
-// { dg-options "" }
+// { dg-do compile }
 
 template<typename> struct A
 {
@@ -9,9 +9,9 @@ template<typename> struct A
 
 template<typename> struct B
 {
-  B(const B&); // { dg-message "candidate" }
-  typedef typename A<char[A<B>::i]>::X Y;
-  template<typename T> B(T, Y); // { dg-error "call" }
+  B(const B&);
+  typedef typename A<char[A<B>::i]>::X Y; // { dg-error "forbids zero-size array" }
+  template<typename T> B(T, Y);
 };
 
-B<int> b(0,0); 
+B<int> b(0,0); // { dg-message "instantiated from here" }
diff --git a/gcc/testsuite/g++.dg/template/typedef11.C b/gcc/testsuite/g++.dg/template/typedef11.C
new file mode 100644
index 0000000..c7c7c98
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/typedef11.C
@@ -0,0 +1,25 @@
+// Author: Dodji Seketeli <dodji@redhat.com>
+// Origin: PR c++/26693
+// { dg-do compile }
+
+
+class Alpha
+{
+  typedef int X; // { dg-error "'typedef int Alpha::X' is private" }
+};
+
+template<int>
+class Beta
+{
+    typedef int Y; // { dg-error "'typedef int Beta<0>::Y' is private" }
+};
+
+template <int>
+int
+bar ()
+{
+  Beta<0>::Y i = 0;
+  return Alpha::X ();
+}
+
+int i = bar<0> (); // { dg-error "within this context" }
diff --git a/gcc/testsuite/g++.dg/template/typedef12.C b/gcc/testsuite/g++.dg/template/typedef12.C
new file mode 100644
index 0000000..3060504
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/typedef12.C
@@ -0,0 +1,23 @@
+// Contributed by Dodji Seketeli <dodji@redhat.com>
+// Origin: Jason Merrill <jason@redhat.com>, PR c++/26693
+// { dg-do compile }
+
+class A
+{
+     protected:
+           typedef int mytype;
+};
+
+template <class T> class B;
+
+class C: public A
+{
+      template <class T> friend class B;
+};
+
+template <class T> class B
+{
+      C::mytype mem;
+};
+
+B<int> b;
diff --git a/gcc/testsuite/g++.dg/template/typedef13.C b/gcc/testsuite/g++.dg/template/typedef13.C
new file mode 100644
index 0000000..aa8bb32
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/typedef13.C
@@ -0,0 +1,16 @@
+// Contributed by Dodji Seketeli <dodji@redhat.com>
+// Origin: PR c++/26693
+// { dg-do compile }
+
+class A
+{
+  typedef int mytype; // { dg-error "typedef int A::mytype' is private" }
+};
+
+template <class T> class B : public A
+{ // { dg-error "within this context"  }
+  mytype mem;
+};
+
+B<int> b; // { dg-message "instantiated from here" }
+
diff --git a/gcc/testsuite/g++.dg/template/typedef14.C b/gcc/testsuite/g++.dg/template/typedef14.C
new file mode 100644
index 0000000..caa565a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/typedef14.C
@@ -0,0 +1,16 @@
+// Contributed by Dodji Seketeli <dodji@redhat.com>
+// Origin: PR c++/26693
+// { dg-do compile }
+
+template <class T>
+struct A
+{
+  typedef int mytype;
+
+  void
+  foo ()
+  {
+    mytype v = ~static_cast<mytype> (0);
+  }
+};
+
diff --git a/gcc/testsuite/g++.old-deja/g++.pt/typename8.C b/gcc/testsuite/g++.old-deja/g++.pt/typename8.C
index 6eb818b..4861cf3 100644
--- a/gcc/testsuite/g++.old-deja/g++.pt/typename8.C
+++ b/gcc/testsuite/g++.old-deja/g++.pt/typename8.C
@@ -5,14 +5,14 @@ template < class T > class A
 public:
   typedef typename T::myT anotherT; // { dg-error "" } undefined type
 
-  anotherT t; // { dg-error "" } undefined type 
+  anotherT t;
 
   A() { }
-  A(anotherT _t) { // { dg-error "" } undefined type
+  A(anotherT _t) {
     t=_t;
   }
 
-  anotherT getT() { // { dg-error "" } undefined type
+  anotherT getT() {
     return t;
   }
 };
diff --git a/gcc/tree.h b/gcc/tree.h
index d85918f..a1d814c 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -3405,6 +3405,9 @@ struct tree_target_option GTY(())
 /* Return a tree node that encapsulates the current target options.  */
 extern tree build_target_option_node (void);
 
+extern void set_underlying_type (tree x);
+
+extern bool is_typedef_type (tree x);
 \f
 /* Define the overall contents of a tree node.
    It may be any of the structures declared above
diff --git a/libstdc++-v3/include/ext/bitmap_allocator.h b/libstdc++-v3/include/ext/bitmap_allocator.h
index 7f5466a..7768bd2 100644
--- a/libstdc++-v3/include/ext/bitmap_allocator.h
+++ b/libstdc++-v3/include/ext/bitmap_allocator.h
@@ -549,11 +549,13 @@ _GLIBCXX_BEGIN_NAMESPACE(__gnu_cxx)
    */
   class free_list
   {
+  public:
     typedef size_t* 				value_type;
     typedef __detail::__mini_vector<value_type> vector_type;
     typedef vector_type::iterator 		iterator;
     typedef __mutex				__mutex_type;
 
+  private:
     struct _LT_pointer_compare
     {
       bool

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH] PR c++/26693
  2008-12-04  0:18                           ` Dodji Seketeli
@ 2008-12-04 14:28                             ` Jason Merrill
  2008-12-04 17:13                               ` Dodji Seketeli
  0 siblings, 1 reply; 17+ messages in thread
From: Jason Merrill @ 2008-12-04 14:28 UTC (permalink / raw)
  To: Dodji Seketeli; +Cc: Gcc Patch List

Dodji Seketeli wrote:
> The test case in the attached patch, in file 
> gcc/testsuite/g++.dg/template/typedef14.C. The assert is hit when 
> calling fold_non_dependent_expr on "~static_cast<mytype> (0)", which 
> eventually calls tsubst on the mytype typedef.
> 
> When we tsubst the mytype typedef, we hit the line:
> tree gen_args = tsubst (DECL_TI_ARGS (decl), args, complain, in_decl);

Ah, OK.  So in this case we're still in the template, so what we want is 
the template version of the typedef, so just adding

if (args == NULL_TREE)
   return t;

to the top of tsubst, or the top of the typedef reuse bit, would give 
the right answer.

> I changed this to actually put the code to append the type the list of 
> access checks for the template into check_accessibility_of_qualified_id, 

I thought about that possibility, but then you don't diagnose

class A
{
  typedef int foo;
};

template <class T>
class B: public A
{
   foo f;
};

>>> +append_type_to_template_for_access_check (tree type,

>> Don't we need to do the same thing in function templates?

> I am not sure to understand why this wouldn't work for typedef types 
> referenced in function templates. Could you please tell me what I am 
> missing ?

I guess I was just confused by the parameter named "type".  Please 
rename it to "tmpl" or some such.  :)

Jason

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH] PR c++/26693
  2008-12-04 14:28                             ` Jason Merrill
@ 2008-12-04 17:13                               ` Dodji Seketeli
  0 siblings, 0 replies; 17+ messages in thread
From: Dodji Seketeli @ 2008-12-04 17:13 UTC (permalink / raw)
  To: Jason Merrill; +Cc: Gcc Patch List

[-- Attachment #1: Type: text/plain, Size: 1836 bytes --]

Jason Merrill a écrit :
> Dodji Seketeli wrote:
>> The test case in the attached patch, in file 
>> gcc/testsuite/g++.dg/template/typedef14.C. The assert is hit when 
>> calling fold_non_dependent_expr on "~static_cast<mytype> (0)", which 
>> eventually calls tsubst on the mytype typedef.
>>
>> When we tsubst the mytype typedef, we hit the line:
>> tree gen_args = tsubst (DECL_TI_ARGS (decl), args, complain, in_decl);
> 
> Ah, OK.  So in this case we're still in the template, so what we want is 
> the template version of the typedef, so just adding
> 
> if (args == NULL_TREE)
>   return t;
> 
> to the top of tsubst, or the top of the typedef reuse bit, would give 
> the right answer.

Okay. I did it in the attached updated patch.

> 
>> I changed this to actually put the code to append the type the list of 
>> access checks for the template into check_accessibility_of_qualified_id, 
> 
> I thought about that possibility, but then you don't diagnose
> 
> class A
> {
>  typedef int foo;
> };
> 
> template <class T>
> class B: public A
> {
>   foo f;
> };
>

I think this case is diagnosed with the attached patch. The test 
gcc/testsuite/g++.dg/template/typedef13.C included in the patch is 
similar to the example you are mentioning and it seems to pass.


>>>> +append_type_to_template_for_access_check (tree type,
> 
>>> Don't we need to do the same thing in function templates?
> 
>> I am not sure to understand why this wouldn't work for typedef types 
>> referenced in function templates. Could you please tell me what I am 
>> missing ?
> 
> I guess I was just confused by the parameter named "type".  Please 
> rename it to "tmpl" or some such.  :)

Yes "type" is not appropriate. I renamed it into templ.

The attached patch passes regtests and compiles libstdc++ on trunk for 
the x86_64 arch.

Thanks,

Dodji.

[-- Attachment #2: PR26693-patch-6.txt --]
[-- Type: text/plain, Size: 26879 bytes --]

gcc/ChangeLog:
2008-12-04  Dodji Seketeli  <dodji@redhat.com>

	PR c++/26693
	* c-decl.c: (clone_underlying_type): Move this  ...
	* c-common.c (set_underlying_type): ... here.
	Also, make sure the function  properly sets TYPE_STUB_DECL() on
	the newly created typedef variant type.
	(is_typedef_type ): New entry point.
	* tree.h: Added a new member member_types_needing_access_check to
	struct tree_decl_non_common.
	(set_underlying_type): New entry point.
	(is_typedef_type): Likewise.

gcc/cp/ChangeLog:
2008-12-04  Dodji Seketeli  <dodji@redhat.com>

	PR c++/26693
	* decl2.c (grokfield): when a typedef appears in a
	class, create the typedef variant type node for it.
	* decl.c (grokdeclarator): If the typedef'ed struct/class was
	anonymous, set the proper type name to all its type variants.
	* name-lookup.c (pushdecl_maybe_friend): Reuse the
	set_underlying_type function to install typedef variant types.
	* cp-tree.h (MEMBER_TYPES_NEEDING_ACCESS_CHECK): New template accessor
	macro.
	(is_class_nested, append_type_to_template_for_access_check): New
	 entry points.
	* semantics.c (check_accessibility_of_qualified_id):
	When a typedef that is a member of a class appears in a template,
	add it to the template. It will be ...
	* pt.c (instantiate_class_template, instantiate_template ): ... access
	checked at template instantiation time.
	(tsubst): Handle the case of being called with NULL args.
	(append_type_to_template_for_access_check): New entry point.
	* search.c (is_class_nested): New entry point.

gcc/testsuite/ChangeLog:
2008-12-04  Dodji Seketeli  <dodji@redhat.com>

	PR c++/26693
	* g++.dg/template/typedef11.C: New test.
	* g++.dg/template/typedef12.C: Likewise.
	* g++.dg/template/typedef13.C: Likewise.
	* g++.dg/template/typedef14.C: Likewise.
	* g++.dg/template/sfinae3.C: Compile this pedantically.
	The only errors expected should be the one saying the typedef is ill
	formed.
	* g++.old-deja/g++.pt/typename8.C: Likewise.
	* g++.dg/template/access11.C: Update this.

libstdc++-v3/ChangeLog:
2008-12-04  Dodji Seketeli  <dodji@redhat.com>

	* include/ext/bitmap_allocator.h: the typedefs should be made public
	if we want them to be accessible. This has been revealed by the patch
	that fixes PR c++/26693 in g++.

diff --git a/gcc/c-common.c b/gcc/c-common.c
index e83b58e..1b605e3 100644
--- a/gcc/c-common.c
+++ b/gcc/c-common.c
@@ -8360,4 +8360,81 @@ warn_for_sign_compare (location_t location,
     }
 }
 
+/* Setup a TYPE_DECL node as a typedef representation.
+
+   X is a TYPE_DECL for a typedef statement.  Create a brand new
+   ..._TYPE node (which will be just a variant of the existing
+   ..._TYPE node with identical properties) and then install X
+   as the TYPE_NAME of this brand new (duplicate) ..._TYPE node.
+
+   The whole point here is to end up with a situation where each
+   and every ..._TYPE node the compiler creates will be uniquely
+   associated with AT MOST one node representing a typedef name.
+   This way, even though the compiler substitutes corresponding
+   ..._TYPE nodes for TYPE_DECL (i.e. "typedef name") nodes very
+   early on, later parts of the compiler can always do the reverse
+   translation and get back the corresponding typedef name.  For
+   example, given:
+
+	typedef struct S MY_TYPE;
+	MY_TYPE object;
+
+   Later parts of the compiler might only know that `object' was of
+   type `struct S' if it were not for code just below.  With this
+   code however, later parts of the compiler see something like:
+
+	struct S' == struct S
+	typedef struct S' MY_TYPE;
+	struct S' object;
+
+    And they can then deduce (from the node for type struct S') that
+    the original object declaration was:
+
+		MY_TYPE object;
+
+    Being able to do this is important for proper support of protoize,
+    and also for generating precise symbolic debugging information
+    which takes full account of the programmer's (typedef) vocabulary.
+
+    Obviously, we don't want to generate a duplicate ..._TYPE node if
+    the TYPE_DECL node that we are now processing really represents a
+    standard built-in type.  */
+
+void
+set_underlying_type (tree x)
+{
+
+  if (DECL_IS_BUILTIN (x))
+    {
+      if (TYPE_NAME (TREE_TYPE (x)) == 0)
+	TYPE_NAME (TREE_TYPE (x)) = x;
+    }
+  else if (TREE_TYPE (x) != error_mark_node
+	   && DECL_ORIGINAL_TYPE (x) == NULL_TREE)
+    {
+      tree tt = TREE_TYPE (x);
+      DECL_ORIGINAL_TYPE (x) = tt;
+      tt = build_variant_type_copy (tt);
+      TYPE_STUB_DECL (tt) = TYPE_STUB_DECL (DECL_ORIGINAL_TYPE (x));
+      TYPE_NAME (tt) = x;
+      TREE_USED (tt) = TREE_USED (x);
+      TREE_TYPE (x) = tt;
+    }
+}
+
+/* Returns true if X is a typedef type.  */
+bool
+is_typedef_type (tree x)
+{
+  return (x
+	  && x != error_mark_node
+	  && TREE_CODE (x) == TYPE_DECL
+	  && TREE_TYPE (x)
+	  && TREE_TYPE (x) != error_mark_node
+	  && TYPE_NAME (TREE_TYPE (x))
+	  && TYPE_MAIN_VARIANT (TREE_TYPE (x))
+	  && TYPE_NAME (TREE_TYPE (x))
+	    != TYPE_STUB_DECL (TYPE_MAIN_VARIANT (TREE_TYPE (x))));
+}
+
 #include "gt-c-common.h"
diff --git a/gcc/c-decl.c b/gcc/c-decl.c
index 6f88f62..3a96195 100644
--- a/gcc/c-decl.c
+++ b/gcc/c-decl.c
@@ -1971,67 +1971,6 @@ warn_if_shadowing (tree new_decl)
       }
 }
 
-
-/* Subroutine of pushdecl.
-
-   X is a TYPE_DECL for a typedef statement.  Create a brand new
-   ..._TYPE node (which will be just a variant of the existing
-   ..._TYPE node with identical properties) and then install X
-   as the TYPE_NAME of this brand new (duplicate) ..._TYPE node.
-
-   The whole point here is to end up with a situation where each
-   and every ..._TYPE node the compiler creates will be uniquely
-   associated with AT MOST one node representing a typedef name.
-   This way, even though the compiler substitutes corresponding
-   ..._TYPE nodes for TYPE_DECL (i.e. "typedef name") nodes very
-   early on, later parts of the compiler can always do the reverse
-   translation and get back the corresponding typedef name.  For
-   example, given:
-
-	typedef struct S MY_TYPE;
-	MY_TYPE object;
-
-   Later parts of the compiler might only know that `object' was of
-   type `struct S' if it were not for code just below.  With this
-   code however, later parts of the compiler see something like:
-
-	struct S' == struct S
-	typedef struct S' MY_TYPE;
-	struct S' object;
-
-    And they can then deduce (from the node for type struct S') that
-    the original object declaration was:
-
-		MY_TYPE object;
-
-    Being able to do this is important for proper support of protoize,
-    and also for generating precise symbolic debugging information
-    which takes full account of the programmer's (typedef) vocabulary.
-
-    Obviously, we don't want to generate a duplicate ..._TYPE node if
-    the TYPE_DECL node that we are now processing really represents a
-    standard built-in type.  */
-
-static void
-clone_underlying_type (tree x)
-{
-  if (DECL_IS_BUILTIN (x))
-    {
-      if (TYPE_NAME (TREE_TYPE (x)) == 0)
-	TYPE_NAME (TREE_TYPE (x)) = x;
-    }
-  else if (TREE_TYPE (x) != error_mark_node
-	   && DECL_ORIGINAL_TYPE (x) == NULL_TREE)
-    {
-      tree tt = TREE_TYPE (x);
-      DECL_ORIGINAL_TYPE (x) = tt;
-      tt = build_variant_type_copy (tt);
-      TYPE_NAME (tt) = x;
-      TREE_USED (tt) = TREE_USED (x);
-      TREE_TYPE (x) = tt;
-    }
-}
-
 /* Record a decl-node X as belonging to the current lexical scope.
    Check for errors (such as an incompatible declaration for the same
    name already seen in the same scope).
@@ -2254,7 +2193,7 @@ pushdecl (tree x)
 
  skip_external_and_shadow_checks:
   if (TREE_CODE (x) == TYPE_DECL)
-    clone_underlying_type (x);
+    set_underlying_type (x);
 
   bind (name, x, scope, /*invisible=*/false, nested);
 
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 9f10ed1..23ef874 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -3178,6 +3178,14 @@ more_aggr_init_expr_args_p (const aggr_init_expr_arg_iterator *iter)
    && TREE_CODE (DECL_TEMPLATE_RESULT (NODE)) == TYPE_DECL \
    && !DECL_TEMPLATE_TEMPLATE_PARM_P (NODE))
 
+/* The chained list of some types that are referenced in templates.
+   These types are those which need to be access checked at
+   template instantiation time.  For the time being, only typedef-ed types defined
+   as class members are put here at parsing time.
+   Other types for which access check could be required at template instantiation
+   time could be added later.  */
+#define MEMBER_TYPES_NEEDING_ACCESS_CHECK(NODE) DECL_ACCESS (NODE)
+
 /* Nonzero if NODE which declares a type.  */
 #define DECL_DECLARES_TYPE_P(NODE) \
   (TREE_CODE (NODE) == TYPE_DECL || DECL_CLASS_TEMPLATE_P (NODE))
@@ -4231,6 +4239,7 @@ extern void pushclass				(tree);
 extern void popclass				(void);
 extern void push_nested_class			(tree);
 extern void pop_nested_class			(void);
+extern bool is_class_nested			(tree, tree);
 extern int current_lang_depth			(void);
 extern void push_lang_context			(tree);
 extern void pop_lang_context			(void);
@@ -4532,6 +4541,7 @@ extern tree check_explicit_specialization	(tree, tree, int, int);
 extern tree make_auto				(void);
 extern tree do_auto_deduction			(tree, tree, tree);
 extern tree type_uses_auto			(tree);
+extern void append_type_to_template_for_access_check (tree, tree, tree);
 extern tree splice_late_return_type		(tree, tree);
 extern bool is_auto				(const_tree);
 extern tree process_template_parm		(tree, tree, bool, bool);
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 997c580..92df629 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -8725,6 +8725,7 @@ grokdeclarator (const cp_declarator *declarator,
 	decl = build_lang_decl (TYPE_DECL, unqualified_id, type);
       else
 	decl = build_decl (TYPE_DECL, unqualified_id, type);
+
       if (id_declarator && declarator->u.id.qualifying_scope) {
 	error ("%Jtypedef name may not be a nested-name-specifier", decl);
 	TREE_TYPE (decl) = error_mark_node;
@@ -8759,12 +8760,11 @@ grokdeclarator (const cp_declarator *declarator,
 	  && TYPE_ANONYMOUS_P (type)
 	  && cp_type_quals (type) == TYPE_UNQUALIFIED)
 	{
-	  tree oldname = TYPE_NAME (type);
 	  tree t;
 
 	  /* Replace the anonymous name with the real name everywhere.  */
 	  for (t = TYPE_MAIN_VARIANT (type); t; t = TYPE_NEXT_VARIANT (t))
-	    if (TYPE_NAME (t) == oldname)
+	    if (ANON_AGGRNAME_P (TYPE_IDENTIFIER (t)))
 	      TYPE_NAME (t) = decl;
 
 	  if (TYPE_LANG_SPECIFIC (type))
diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c
index da9201e..4d92e4b 100644
--- a/gcc/cp/decl2.c
+++ b/gcc/cp/decl2.c
@@ -804,6 +804,9 @@ grokfield (const cp_declarator *declarator,
       DECL_NONLOCAL (value) = 1;
       DECL_CONTEXT (value) = current_class_type;
 
+      if (declspecs->specs[(int)ds_typedef])
+	set_underlying_type (value);
+
       if (processing_template_decl)
 	value = push_template_decl (value);
 
@@ -1125,19 +1128,6 @@ save_template_attributes (tree *attr_p, tree *decl_p)
   if (!late_attrs)
     return;
 
-  /* Give this type a name so we know to look it up again at instantiation
-     time.  */
-  if (TREE_CODE (*decl_p) == TYPE_DECL
-      && DECL_ORIGINAL_TYPE (*decl_p) == NULL_TREE)
-    {
-      tree oldt = TREE_TYPE (*decl_p);
-      tree newt = build_variant_type_copy (oldt);
-      DECL_ORIGINAL_TYPE (*decl_p) = oldt;
-      TREE_TYPE (*decl_p) = newt;
-      TYPE_NAME (newt) = *decl_p;
-      TREE_USED (newt) = TREE_USED (*decl_p);
-    }
-
   if (DECL_P (*decl_p))
     q = &DECL_ATTRIBUTES (*decl_p);
   else
diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c
index 0da373c..d9ea96d 100644
--- a/gcc/cp/name-lookup.c
+++ b/gcc/cp/name-lookup.c
@@ -847,28 +847,20 @@ pushdecl_maybe_friend (tree x, bool is_friend)
 
       /* If declaring a type as a typedef, copy the type (unless we're
 	 at line 0), and install this TYPE_DECL as the new type's typedef
-	 name.  See the extensive comment in ../c-decl.c (pushdecl).  */
+	 name.  See the extensive comment of set_underlying_type ().  */
       if (TREE_CODE (x) == TYPE_DECL)
 	{
 	  tree type = TREE_TYPE (x);
-	  if (DECL_IS_BUILTIN (x))
-	    {
-	      if (TYPE_NAME (type) == 0)
-		TYPE_NAME (type) = x;
-	    }
-	  else if (type != error_mark_node && TYPE_NAME (type) != x
-		   /* We don't want to copy the type when all we're
-		      doing is making a TYPE_DECL for the purposes of
-		      inlining.  */
-		   && (!TYPE_NAME (type)
-		       || TYPE_NAME (type) != DECL_ABSTRACT_ORIGIN (x)))
-	    {
-	      DECL_ORIGINAL_TYPE (x) = type;
-	      type = build_variant_type_copy (type);
-	      TYPE_STUB_DECL (type) = TYPE_STUB_DECL (DECL_ORIGINAL_TYPE (x));
-	      TYPE_NAME (type) = x;
-	      TREE_TYPE (x) = type;
-	    }
+
+	  if (DECL_IS_BUILTIN (x)
+	      || (TREE_TYPE (x) != error_mark_node
+		  && TYPE_NAME (type) != x
+		  /* We don't want to copy the type when all we're
+		     doing is making a TYPE_DECL for the purposes of
+		     inlining.  */
+		  && (!TYPE_NAME (type)
+		      || TYPE_NAME (type) != DECL_ABSTRACT_ORIGIN (x))))
+	    set_underlying_type (x);
 
 	  if (type != error_mark_node
 	      && TYPE_NAME (type)
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index 8fdd58c..aa2fad5 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -11367,7 +11367,7 @@ cp_parser_nonclass_name (cp_parser* parser)
   else if (type_decl != error_mark_node
 	   && !parser->scope)
     maybe_note_name_used_in_class (identifier, type_decl);
-  
+
   return type_decl;
 }
 
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 127d37c..163d8db 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -7320,6 +7320,31 @@ instantiate_class_template (tree type)
 	  && DECL_TEMPLATE_INFO (t))
 	tsubst_default_arguments (t);
 
+  /* Some types referenced from within the template code need to be access
+     checked at template instantiation time, i.e now. These types were
+     added to the template at parsing time. Let's get those and perfom
+     the acces checks then.  */
+  for (t = MEMBER_TYPES_NEEDING_ACCESS_CHECK (templ); t; t = TREE_CHAIN (t))
+    {
+      tree type_decl = TREE_PURPOSE (t);
+      tree type_scope = TREE_VALUE (t);
+
+      if (!type_decl || !type_scope || !CLASS_TYPE_P (type_scope))
+	continue;
+
+      if (uses_template_parms (type_decl))
+	type_decl = tsubst (type_decl, args, tf_error, NULL_TREE);
+
+      if (uses_template_parms (type_scope))
+	type_scope = tsubst (type_scope, args, tf_error, NULL_TREE);
+
+      gcc_assert (type_decl && type_decl != error_mark_node
+		  && type_scope && type_scope != error_mark_node);
+
+      perform_or_defer_access_check (TYPE_BINFO (type_scope), type_decl, type_decl);
+    }
+
+  perform_deferred_access_checks ();
   pop_nested_class ();
   pop_from_top_level ();
   pop_deferring_access_checks ();
@@ -8902,7 +8927,8 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl)
       || t == void_type_node
       || t == char_type_node
       || t == unknown_type_node
-      || TREE_CODE (t) == NAMESPACE_DECL)
+      || TREE_CODE (t) == NAMESPACE_DECL
+      || args == NULL)
     return t;
 
   if (DECL_P (t))
@@ -8922,7 +8948,7 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl)
       && TYPE_NAME (t) != TYPE_MAIN_DECL (t))
     {
       tree decl = TYPE_NAME (t);
-      
+
       if (DECL_CLASS_SCOPE_P (decl)
 	  && CLASSTYPE_TEMPLATE_INFO (DECL_CONTEXT (decl))
 	  && uses_template_parms (DECL_CONTEXT (decl)))
@@ -9040,7 +9066,7 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl)
 	r = NULL_TREE;
 
 	gcc_assert (TREE_VEC_LENGTH (args) > 0);
-	template_parm_level_and_index (t, &level, &idx); 
+	template_parm_level_and_index (t, &level, &idx);
 
 	levels = TMPL_ARGS_DEPTH (args);
 	if (level <= levels)
@@ -11763,6 +11789,7 @@ instantiate_template (tree tmpl, tree targ_ptr, tsubst_flags_t complain)
   tree fndecl;
   tree gen_tmpl;
   tree spec;
+  tree t;
   HOST_WIDE_INT saved_processing_template_decl;
 
   if (tmpl == error_mark_node)
@@ -11841,6 +11868,24 @@ instantiate_template (tree tmpl, tree targ_ptr, tsubst_flags_t complain)
   /* Now we know the specialization, compute access previously
      deferred.  */
   push_access_scope (fndecl);
+
+  /* Some types referenced from within the template code need to be access
+     checked at template instantiation time, i.e now. These types were
+     added to the template at parsing time. Let's get those and perfom
+     the acces checks then.  */
+  for (t = MEMBER_TYPES_NEEDING_ACCESS_CHECK (tmpl); t; t = TREE_CHAIN (t))
+    {
+      tree type_decl = TREE_PURPOSE (t);
+      tree type_scope = TREE_VALUE (t);
+
+      if (!type_decl || !type_scope || !CLASS_TYPE_P (type_scope))
+	continue;
+
+      if (uses_template_parms (type_decl))
+	type_decl = tsubst (type_decl, targ_ptr, tf_error, NULL_TREE);
+
+      perform_or_defer_access_check (TYPE_BINFO (type_scope), type_decl, type_decl);
+    }
   perform_deferred_access_checks ();
   pop_access_scope (fndecl);
   pop_deferring_access_checks ();
@@ -16527,7 +16572,16 @@ resolve_typename_type (tree type, bool only_current_p)
   gcc_assert (TREE_CODE (type) == TYPENAME_TYPE);
 
   scope = TYPE_CONTEXT (type);
-  name = TYPE_IDENTIFIER (type);
+  /* Usually the non-qualified identifier of a TYPENAME_TYPE is
+     TYPE_IDENTIFIER (type). But when 'type' is a typedef variant of
+     a TYPENAME_TYPE node, then TYPE_NAME (type) is set to the TYPE_DECL representing
+     the typedef. In that case TYPE_IDENTIFIER (type) is not the non-qualified
+     identifier  of the TYPENAME_TYPE anymore.
+     So by getting the TYPE_IDENTIFIER of the _main declaration_ of the
+     TYPENAME_TYPE instead, we avoid messing up with a possible
+     typedef variant case.  */
+  /*name = TYPE_IDENTIFIER (TREE_TYPE (TYPE_MAIN_DECL (type)));*/
+  name = TYPE_IDENTIFIER (TYPE_MAIN_VARIANT (type));
 
   /* If the SCOPE is itself a TYPENAME_TYPE, then we need to resolve
      it first before we can figure out what NAME refers to.  */
@@ -16852,4 +16906,45 @@ type_uses_auto (tree type)
   return NULL_TREE;
 }
 
+/* Append TYPE_DECL to the template TMPL.
+   TMPL is eiter a class type or a FUNCTION_DECL associated
+   to a TEMPLATE_DECL.
+   At TMPL instanciation time, TYPE_DECL will be checked to see
+   if it can be accessed through SCOPE.  */
+void
+append_type_to_template_for_access_check (tree templ,
+                                          tree type_decl,
+					  tree scope)
+{
+  tree node, templ_decl;
+
+  gcc_assert (templ
+	      && get_template_info (templ)
+	      && TI_TEMPLATE (get_template_info (templ))
+	      && type_decl
+	      && (TREE_CODE (type_decl) == TYPE_DECL));
+
+  templ_decl = TI_TEMPLATE (get_template_info (templ));
+  gcc_assert (templ_decl);
+
+  /* Make sure we don't append the type to the template twice.
+     If this appears to be too slow, the
+     MEMBER_TYPE_NEEDING_ACCESS_CHECK property
+     of templ should be a hash table instead.  */
+  for (node = MEMBER_TYPES_NEEDING_ACCESS_CHECK (templ_decl);
+       node;
+       node = TREE_CHAIN (node))
+    {
+      tree decl = TREE_PURPOSE (node);
+      tree type_scope = TREE_VALUE (node);
+
+      if (decl == type_decl && type_scope == scope)
+	return;
+    }
+
+  node = build_tree_list (type_decl, scope);
+  MEMBER_TYPES_NEEDING_ACCESS_CHECK (templ_decl) =
+    chainon (node, MEMBER_TYPES_NEEDING_ACCESS_CHECK (templ_decl));
+}
+
 #include "gt-cp-pt.h"
diff --git a/gcc/cp/search.c b/gcc/cp/search.c
index 7fc040b..1cce251 100644
--- a/gcc/cp/search.c
+++ b/gcc/cp/search.c
@@ -2623,3 +2623,20 @@ original_binfo (tree binfo, tree here)
   return result;
 }
 
+/* Returns true if NESTED is a nested class of BASE, false otherwise.  */
+bool
+is_class_nested (tree base, tree nested)
+{
+  tree t;
+
+  if (!base || !nested
+    || !CLASS_TYPE_P (base)
+    || !CLASS_TYPE_P (nested))
+    return false;
+
+  for (t = TYPE_CONTEXT (nested); t && TYPE_P (t); t = TYPE_CONTEXT (t))
+    if (same_type_p (t, base))
+      return true;
+  return false;
+}
+
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index e0ae6ff..5ed41c1 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -1524,6 +1524,38 @@ check_accessibility_of_qualified_id (tree decl,
   tree scope;
   tree qualifying_type = NULL_TREE;
 
+  /* If we are parsing a template declaration and if decl is a typedef,
+     add it to a list tied to the template.
+     At template instantiation time, that list will be walked and
+     access check performed.  */
+  if (is_typedef_type (decl))
+    {
+      /* This the scope through which type_decl is accessed.
+	 It will be useful information later to do access check for
+	 type_decl usage.  */
+      tree scope = nested_name_specifier ? nested_name_specifier : DECL_CONTEXT (decl);
+      tree templ_info = NULL;
+      tree templ_type = NULL;
+
+      if (current_function_decl)
+	templ_type = current_function_decl;
+      else if (current_class_type)
+	templ_type = current_class_type;
+      if (templ_type)
+	templ_info = get_template_info (templ_type);
+
+      if (templ_info
+	  && TI_TEMPLATE (templ_info)
+	  && scope
+	  && CLASS_TYPE_P (scope)
+	  && ((current_class_type
+	       && !same_type_p (scope, current_class_type)
+	       && !is_class_nested (scope, current_class_type))
+	      || (current_function_decl
+		  && !DECL_FUNCTION_MEMBER_P (current_function_decl))))
+	append_type_to_template_for_access_check (templ_type, decl, scope);
+    }
+
   /* If we're not checking, return immediately.  */
   if (deferred_access_no_check)
     return;
diff --git a/gcc/testsuite/g++.dg/template/access11.C b/gcc/testsuite/g++.dg/template/access11.C
index 4c8dce5..38bd515 100644
--- a/gcc/testsuite/g++.dg/template/access11.C
+++ b/gcc/testsuite/g++.dg/template/access11.C
@@ -17,8 +17,8 @@ template <> struct X::Y<int> {
   A::X x;			// { dg-error "this context" }
 };
 
-template <typename T> struct X::Y {
+template <typename T> struct X::Y { // { dg-error "this context" }
   typename T::X x;		// { dg-error "this context" }
 };
 
-template struct X::Y<A>;	// { dg-message "instantiated" }
+template struct X::Y<A>;	// { dg-message "instantiated from here" }
diff --git a/gcc/testsuite/g++.dg/template/sfinae3.C b/gcc/testsuite/g++.dg/template/sfinae3.C
index 5799a36..349463d 100644
--- a/gcc/testsuite/g++.dg/template/sfinae3.C
+++ b/gcc/testsuite/g++.dg/template/sfinae3.C
@@ -1,5 +1,5 @@
 // PR c++/24671
-// { dg-options "" }
+// { dg-do compile }
 
 template<typename> struct A
 {
@@ -9,9 +9,9 @@ template<typename> struct A
 
 template<typename> struct B
 {
-  B(const B&); // { dg-message "candidate" }
-  typedef typename A<char[A<B>::i]>::X Y;
-  template<typename T> B(T, Y); // { dg-error "call" }
+  B(const B&);
+  typedef typename A<char[A<B>::i]>::X Y; // { dg-error "forbids zero-size array" }
+  template<typename T> B(T, Y);
 };
 
-B<int> b(0,0); 
+B<int> b(0,0); // { dg-message "instantiated from here" }
diff --git a/gcc/testsuite/g++.dg/template/typedef11.C b/gcc/testsuite/g++.dg/template/typedef11.C
new file mode 100644
index 0000000..c7c7c98
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/typedef11.C
@@ -0,0 +1,25 @@
+// Author: Dodji Seketeli <dodji@redhat.com>
+// Origin: PR c++/26693
+// { dg-do compile }
+
+
+class Alpha
+{
+  typedef int X; // { dg-error "'typedef int Alpha::X' is private" }
+};
+
+template<int>
+class Beta
+{
+    typedef int Y; // { dg-error "'typedef int Beta<0>::Y' is private" }
+};
+
+template <int>
+int
+bar ()
+{
+  Beta<0>::Y i = 0;
+  return Alpha::X ();
+}
+
+int i = bar<0> (); // { dg-error "within this context" }
diff --git a/gcc/testsuite/g++.dg/template/typedef12.C b/gcc/testsuite/g++.dg/template/typedef12.C
new file mode 100644
index 0000000..3060504
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/typedef12.C
@@ -0,0 +1,23 @@
+// Contributed by Dodji Seketeli <dodji@redhat.com>
+// Origin: Jason Merrill <jason@redhat.com>, PR c++/26693
+// { dg-do compile }
+
+class A
+{
+     protected:
+           typedef int mytype;
+};
+
+template <class T> class B;
+
+class C: public A
+{
+      template <class T> friend class B;
+};
+
+template <class T> class B
+{
+      C::mytype mem;
+};
+
+B<int> b;
diff --git a/gcc/testsuite/g++.dg/template/typedef13.C b/gcc/testsuite/g++.dg/template/typedef13.C
new file mode 100644
index 0000000..aa8bb32
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/typedef13.C
@@ -0,0 +1,16 @@
+// Contributed by Dodji Seketeli <dodji@redhat.com>
+// Origin: PR c++/26693
+// { dg-do compile }
+
+class A
+{
+  typedef int mytype; // { dg-error "typedef int A::mytype' is private" }
+};
+
+template <class T> class B : public A
+{ // { dg-error "within this context"  }
+  mytype mem;
+};
+
+B<int> b; // { dg-message "instantiated from here" }
+
diff --git a/gcc/testsuite/g++.dg/template/typedef14.C b/gcc/testsuite/g++.dg/template/typedef14.C
new file mode 100644
index 0000000..caa565a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/typedef14.C
@@ -0,0 +1,16 @@
+// Contributed by Dodji Seketeli <dodji@redhat.com>
+// Origin: PR c++/26693
+// { dg-do compile }
+
+template <class T>
+struct A
+{
+  typedef int mytype;
+
+  void
+  foo ()
+  {
+    mytype v = ~static_cast<mytype> (0);
+  }
+};
+
diff --git a/gcc/testsuite/g++.old-deja/g++.pt/typename8.C b/gcc/testsuite/g++.old-deja/g++.pt/typename8.C
index 6eb818b..4861cf3 100644
--- a/gcc/testsuite/g++.old-deja/g++.pt/typename8.C
+++ b/gcc/testsuite/g++.old-deja/g++.pt/typename8.C
@@ -5,14 +5,14 @@ template < class T > class A
 public:
   typedef typename T::myT anotherT; // { dg-error "" } undefined type
 
-  anotherT t; // { dg-error "" } undefined type 
+  anotherT t;
 
   A() { }
-  A(anotherT _t) { // { dg-error "" } undefined type
+  A(anotherT _t) {
     t=_t;
   }
 
-  anotherT getT() { // { dg-error "" } undefined type
+  anotherT getT() {
     return t;
   }
 };
diff --git a/gcc/tree.h b/gcc/tree.h
index d85918f..a1d814c 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -3405,6 +3405,9 @@ struct tree_target_option GTY(())
 /* Return a tree node that encapsulates the current target options.  */
 extern tree build_target_option_node (void);
 
+extern void set_underlying_type (tree x);
+
+extern bool is_typedef_type (tree x);
 \f
 /* Define the overall contents of a tree node.
    It may be any of the structures declared above
diff --git a/libstdc++-v3/include/ext/bitmap_allocator.h b/libstdc++-v3/include/ext/bitmap_allocator.h
index 7f5466a..7768bd2 100644
--- a/libstdc++-v3/include/ext/bitmap_allocator.h
+++ b/libstdc++-v3/include/ext/bitmap_allocator.h
@@ -549,11 +549,13 @@ _GLIBCXX_BEGIN_NAMESPACE(__gnu_cxx)
    */
   class free_list
   {
+  public:
     typedef size_t* 				value_type;
     typedef __detail::__mini_vector<value_type> vector_type;
     typedef vector_type::iterator 		iterator;
     typedef __mutex				__mutex_type;
 
+  private:
     struct _LT_pointer_compare
     {
       bool

^ permalink raw reply	[flat|nested] 17+ messages in thread

end of thread, other threads:[~2008-12-04 17:13 UTC | newest]

Thread overview: 17+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2008-10-29 23:22 [PATCH] PR c++/26693 Dodji Seketeli
2008-10-30  0:20 ` Manuel López-Ibáñez
2008-10-31  4:12   ` Dodji Seketeli
2008-11-03 18:56     ` Jason Merrill
2008-11-12 14:49       ` Dodji Seketeli
2008-11-12 21:51         ` Jason Merrill
2008-11-13  0:24           ` Dodji Seketeli
2008-11-13 20:34             ` Jason Merrill
2008-11-17 13:12               ` Dodji Seketeli
2008-11-17 17:39                 ` Jason Merrill
2008-11-17 22:14                   ` Dodji Seketeli
2008-11-18 17:47                     ` Jason Merrill
2008-11-30 14:14                       ` Dodji Seketeli
2008-12-02 17:06                         ` Jason Merrill
2008-12-04  0:18                           ` Dodji Seketeli
2008-12-04 14:28                             ` Jason Merrill
2008-12-04 17:13                               ` Dodji Seketeli

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).