diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index ebcd865e9b37fdeb801a2db998bd667f4176f12e..efad3f3e59ae9b084e3ced2e43200db565797ec3 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,16 @@
+2007-09-19  Jason Merrill  <jason@redhat.com>
+
+	PR c++/7586
+	* pt.c (tsubst): Handle typedefs by looking for the specialization.
+	(retrieve_specialization): Only tagged types use 
+	DECL_TEMPLATE_INSTANTIATIONS.
+	(instantiate_class_template): Push nested classes too.
+	(tsubst_decl) [TYPE_DECL]: Only check for canonical decl for
+	tagged types.
+	* cp-tree.h (MAYBE_TAGGED_TYPE_P): New macro.
+	* init.c (is_aggr_type): Remove redundant tests.
+	* class.c (push_nested_class): Use CLASS_TYPE_P.
+
 2007-09-20  Paolo Carlini  <pcarlini@suse.de>
 
 	PR c++/33459
diff --git a/gcc/cp/class.c b/gcc/cp/class.c
index 9e0502fd1fb27b4e2d4a5ce63d87d2fcae337da0..5c3e0548044fd3f863e4a3ab5b3ff68af7aab148 100644
--- a/gcc/cp/class.c
+++ b/gcc/cp/class.c
@@ -5645,21 +5645,13 @@ currently_open_derived_class (tree t)
 void
 push_nested_class (tree type)
 {
-  tree context;
-
   /* A namespace might be passed in error cases, like A::B:C.  */
   if (type == NULL_TREE
-      || type == error_mark_node
-      || TREE_CODE (type) == NAMESPACE_DECL
-      || ! IS_AGGR_TYPE (type)
-      || TREE_CODE (type) == TEMPLATE_TYPE_PARM
-      || TREE_CODE (type) == BOUND_TEMPLATE_TEMPLATE_PARM)
+      || !CLASS_TYPE_P (type))
     return;
 
-  context = DECL_CONTEXT (TYPE_MAIN_DECL (type));
+  push_nested_class (DECL_CONTEXT (TYPE_MAIN_DECL (type)));
 
-  if (context && CLASS_TYPE_P (context))
-    push_nested_class (context);
   pushclass (type);
 }
 
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 4f1e88c931e5827fbec67854019c478e61f4844b..1ddf88492c6495170cb319e14b374482d5170d1f 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -988,6 +988,10 @@ enum languages { lang_c, lang_cplusplus, lang_java };
   ((T) == RECORD_TYPE || (T) == UNION_TYPE)
 #define TAGGED_TYPE_P(T) \
   (CLASS_TYPE_P (T) || TREE_CODE (T) == ENUMERAL_TYPE)
+/* A tagged type or a dependent type that might be a tagged type when
+   instantiated.  Like IS_AGGR_TYPE, but include enums as well.  */
+#define MAYBE_TAGGED_TYPE_P(T) \
+  (IS_AGGR_TYPE(T) || TREE_CODE (T) == ENUMERAL_TYPE)
 #define IS_OVERLOAD_TYPE(T) TAGGED_TYPE_P (T)
 
 /* True if this a "Java" type, defined in 'extern "Java"'.  */
diff --git a/gcc/cp/init.c b/gcc/cp/init.c
index 247879cc5a03d29e39d4387b140eb4b364bd7326..c5c17b1a9e15a8928a9651b490be19fcb630a2b2 100644
--- a/gcc/cp/init.c
+++ b/gcc/cp/init.c
@@ -1281,9 +1281,7 @@ is_aggr_type (tree type, int or_else)
   if (type == error_mark_node)
     return 0;
 
-  if (! IS_AGGR_TYPE (type)
-      && TREE_CODE (type) != TEMPLATE_TYPE_PARM
-      && TREE_CODE (type) != BOUND_TEMPLATE_TEMPLATE_PARM)
+  if (! IS_AGGR_TYPE (type))
     {
       if (or_else)
 	error ("%qT is not an aggregate type", type);
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index e54bc5fba1ed5ad0d57ed482a29d50cae2768daa..17acbaf220d3e859a26864df53bf15318e840de6 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -930,7 +930,8 @@ retrieve_specialization (tree tmpl, tree args,
 	 DECL_TEMPLATE_INSTANTIATIONS list; other templates use the
 	 DECL_TEMPLATE_SPECIALIZATIONS list.  */
       if (!class_specializations_p
-	  && TREE_CODE (DECL_TEMPLATE_RESULT (tmpl)) == TYPE_DECL)
+	  && TREE_CODE (DECL_TEMPLATE_RESULT (tmpl)) == TYPE_DECL
+	  && TAGGED_TYPE_P (TREE_TYPE (tmpl)))
 	sp = &DECL_TEMPLATE_INSTANTIATIONS (tmpl);
       else
 	sp = &DECL_TEMPLATE_SPECIALIZATIONS (tmpl);
@@ -6688,8 +6689,8 @@ instantiate_class_template (tree type)
      class, so that name lookups into base classes, etc. will work
      correctly.  This is precisely analogous to what we do in
      begin_class_definition when defining an ordinary non-template
-     class.  */
-  pushclass (type);
+     class, except we also need to push the enclosing classes.  */
+  push_nested_class (type);
 
   /* Now members are processed in the order of declaration.  */
   for (member = CLASSTYPE_DECL_LIST (pattern);
@@ -6986,7 +6987,7 @@ instantiate_class_template (tree type)
 	  && DECL_TEMPLATE_INFO (t))
 	tsubst_default_arguments (t);
 
-  popclass ();
+  pop_nested_class ();
   pop_from_top_level ();
   pop_deferring_access_checks ();
   pop_tinst_level ();
@@ -8083,7 +8084,8 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain)
 	tree type = NULL_TREE;
 	bool local_p;
 
-	if (TREE_CODE (t) == TYPE_DECL)
+	if (TREE_CODE (t) == TYPE_DECL
+	    && MAYBE_TAGGED_TYPE_P (TREE_TYPE (t)))
 	  {
 	    type = tsubst (TREE_TYPE (t), args, complain, in_decl);
 	    if (TREE_CODE (type) == TEMPLATE_TEMPLATE_PARM
@@ -8158,6 +8160,8 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain)
 
 	/* Create a new node for the specialization we need.  */
 	r = copy_decl (t);
+	if (type == NULL_TREE)
+	  type = tsubst (TREE_TYPE (t), args, complain, in_decl);
 	if (TREE_CODE (r) == VAR_DECL)
 	  {
 	    /* Even if the original location is out of scope, the
@@ -8165,7 +8169,6 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain)
 	    DECL_DEAD_FOR_LOCAL (r) = 0;
 	    DECL_INITIALIZED_P (r) = 0;
 	    DECL_TEMPLATE_INSTANTIATED (r) = 0;
-	    type = tsubst (TREE_TYPE (t), args, complain, in_decl);
 	    if (type == error_mark_node)
 	      return error_mark_node;
 	    if (TREE_CODE (type) == FUNCTION_TYPE)
@@ -8551,41 +8554,36 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl)
 
   gcc_assert (type != unknown_type_node);
 
-  /* Reuse typedefs.  This is a rather complicated way to check whether the
-     type is a typedef from the same class template as the current scope,
-     but I can't think of a better one.
-
-     We need to do this to handle dependent attributes, specifically
-     attribute aligned.  */
+  /* Reuse typedefs.  We need to do this to handle dependent attributes,
+     specifically attribute aligned.  */
   if (TYPE_P (t)
       && TYPE_NAME (t)
-      && !IS_AGGR_TYPE (t)
-      && current_class_type
-      && CLASSTYPE_TEMPLATE_INFO (current_class_type))
+      && !MAYBE_TAGGED_TYPE_P (t)
+      && TREE_CODE (t) != TEMPLATE_TEMPLATE_PARM
+      && TREE_CODE (t) != UNBOUND_CLASS_TEMPLATE)
     {
       tree decl = TYPE_NAME (t);
-      tree context = DECL_CONTEXT (decl);
-      if (context
-	  && CLASS_TYPE_P (context)
-	  && CLASSTYPE_TEMPLATE_INFO (context)
-	  && (CLASSTYPE_TI_TEMPLATE (context)
-	      == CLASSTYPE_TI_TEMPLATE (current_class_type))
-	  && (tsubst_aggr_type (context, args, complain, in_decl,
-				/*entering_scope=*/0)
-	      == current_class_type))
-	    {
-	      r = lookup_name (DECL_NAME (decl));
-	      if (r && TREE_CODE (r) == TYPE_DECL
-		  && DECL_CONTEXT (r) == current_class_type)
-		{
-		  r = TREE_TYPE (r);
-		  r = cp_build_qualified_type_real
-		    (r, cp_type_quals (t) | cp_type_quals (r),
-		     complain | tf_ignore_bad_quals);
-		  return r;
-		  /* Else we're instantiating the typedef, so fall through.  */
-		}
-	    }
+      
+      if (DECL_CLASS_SCOPE_P (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);
+	}
+      else if (DECL_FUNCTION_SCOPE_P (decl))
+	r = retrieve_local_specialization (decl);
+      else
+	r = NULL_TREE;
+	
+      if (r)
+	{
+	  r = TREE_TYPE (r);
+	  r = cp_build_qualified_type_real
+	    (r, cp_type_quals (t) | cp_type_quals (r),
+	     complain | tf_ignore_bad_quals);
+	  return r;
+	}
+      /* Else we must be instantiating the typedef, so fall through.  */
     }
 
   if (type
diff --git a/gcc/testsuite/g++.dg/ext/tmplattr3.C b/gcc/testsuite/g++.dg/ext/tmplattr3.C
index 51f5daf19b1576941737312cf46bd0a725a3a4cb..f8d3c162072f238d67bf327969bc977469465354 100644
--- a/gcc/testsuite/g++.dg/ext/tmplattr3.C
+++ b/gcc/testsuite/g++.dg/ext/tmplattr3.C
@@ -14,8 +14,29 @@ struct Y {
   layout_type data;
 };
 
+template<typename T>
+struct Z {
+  typedef char layout_type[sizeof(T)]
+  __attribute ((aligned(__alignof(T))));
+  struct Z2 {
+    layout_type data;
+  } in;
+};
+
+template<typename T>
+struct A;
+
+template <typename T>
+struct A<T*> {
+  typedef char layout_type[sizeof(T)]
+  __attribute ((aligned(__alignof(T))));
+  layout_type data;
+};
+
 template<bool> struct StaticAssert;
 template<> struct StaticAssert<true> {};
 
 StaticAssert<__alignof(X<double>) == __alignof(double)> d1;
 StaticAssert<__alignof(Y<double>) == __alignof(double)> d2;
+StaticAssert<__alignof(Z<double>) == __alignof(double)> d3;
+StaticAssert<__alignof(A<double*>) == __alignof(double)> d4;
diff --git a/gcc/testsuite/g++.dg/ext/tmplattr4.C b/gcc/testsuite/g++.dg/ext/tmplattr4.C
new file mode 100644
index 0000000000000000000000000000000000000000..3d5c6b7d5fbd718767521669b0320a72c9333519
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/tmplattr4.C
@@ -0,0 +1,19 @@
+// PR c++/7586
+// { dg-do run }
+
+template<typename T>
+int f()
+{
+  typedef unsigned char type[sizeof (T)]
+    __attribute((aligned(__alignof(T))));
+
+  return __alignof (type);
+}
+
+int main()
+{
+  if (f<int>() == __alignof (int))
+    return 0;
+  else
+    return 1;
+}