diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 2c146e34a2deb720a9e67baf4c6d23faee37f360..f70308988af2e6d04050d0f396067a66ad8f2ef2 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,5 +1,16 @@
 1999-10-21  Mark Mitchell  <mark@codesourcery.com>
 
+	* cp-tree.h (SCOPE_PARTIAL_P): New macro.
+	(pushlevel_temporary): Remove.
+	(add_scope_stmt): New function.
+	* decl.c (pushlevel_temporary): Remove.
+	(poplevel): Use add_scope_stmt.
+	(start_decl_1): Likewise.
+	* semantics.c (add_scope_stmt): New function.
+	(do_pushlevel): Use it.
+	(do_poplevel): Use it.
+	(expand_stmt): Check SCOPE_PARTIAL_P.
+	
 	* cp-tree.def (EMPTY_CLASS_EXPR): New tree node.
 	* call.c (build_call): Use EMPTY_CLASS_EXPR instead of RTL_EXPR.
 	* expr.c (cplus_expand_expr): Expand it.
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 425ca18dcbd8296238050b00d49cb9c670069796..b71c162101998ba46de3cea0c391c150f4baab39 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -69,6 +69,7 @@ Boston, MA 02111-1307, USA.  */
       TREE_HAS_CONSTRUCTOR (in INDIRECT_REF, SAVE_EXPR, CONSTRUCTOR,
           or FIELD_DECL).
       NEED_TEMPORARY_P (in REF_BIND, BASE_CONV)
+      SCOPE_PARTIAL_P (in SCOPE_STMT)
    5: Not used.
    6: Not used.
 
@@ -2651,6 +2652,21 @@ extern int flag_new_for_scope;
 #define SCOPE_NULLIFIED_P(NODE) \
   (TREE_LANG_FLAG_3 (SCOPE_STMT_CHECK (NODE)))
 
+/* Nonzero for a SCOPE_STMT if this statement is for a partial scope.
+   For example, in:
+  
+     S s;
+     l:
+     S s2;
+     goto l;
+
+   there is (implicitly) a new scope after `l', even though there are
+   no curly braces.  In particular, when we hit the goto, we must
+   destroy s2 and then re-construct it.  For the implicit scope,
+   SCOPE_PARTIAL_P will be set.  */
+#define SCOPE_PARTIAL_P(NODE) \
+  (TREE_LANG_FLAG_4 (SCOPE_STMT_CHECK (NODE)))
+
 /* Nonzero for an ASM_STMT if the assembly statement is volatile.  */
 #define ASM_VOLATILE_P(NODE)			\
   (ASM_CV_QUAL (ASM_STMT_CHECK (NODE)) != NULL_TREE)
@@ -3336,7 +3352,6 @@ extern int pseudo_global_level_p		PROTO((void));
 extern void set_class_shadows			PROTO((tree));
 extern void pushlevel				PROTO((int));
 extern void note_level_for_for			PROTO((void));
-extern void pushlevel_temporary			PROTO((int));
 extern void resume_level			PROTO((struct binding_level *));
 extern void delete_block			PROTO((tree));
 extern void insert_block			PROTO((tree));
@@ -3886,6 +3901,7 @@ extern void expand_body                         PROTO((tree));
 extern void begin_stmt_tree                     PROTO((tree *));
 extern void finish_stmt_tree                    PROTO((tree *));
 extern void prep_stmt                           PROTO((tree));
+extern void add_scope_stmt                      PROTO((int, int));
 extern void do_pushlevel                        PROTO((void));
 extern tree do_poplevel                         PROTO((void));
 /* Non-zero if we are presently building a statement tree, rather
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 122b0251ac788fec8f63a2a20882466c4322cade..746e498e212a1b367a8896ae94c2d928701afcad 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -825,21 +825,6 @@ note_level_for_for ()
   current_binding_level->is_for_scope = 1;
 }
 
-void
-pushlevel_temporary (tag_transparent)
-     int tag_transparent;
-{
-  pushlevel (tag_transparent);
-  current_binding_level->keep = 2;
-  clear_last_expr ();
-
-  /* Note we don't call push_momentary() here.  Otherwise, it would cause
-     cleanups to be allocated on the momentary obstack, and they will be
-     overwritten by the next statement.  */
-
-  expand_start_bindings (0);
-}
-
 /* For a binding between a name and an entity at a block scope,
    this is the `struct binding_level' for the block.  */
 #define BINDING_LEVEL(NODE) \
@@ -1458,13 +1443,13 @@ poplevel (keep, reverse, functionbody)
   /* Take care of compiler's internal binding structures.  */
   if (tmp == 2)
     {
-      expand_end_bindings (getdecls (), keep, 1);
+      add_scope_stmt (/*begin_p=*/0, /*partial_p=*/1);
       /* Each and every BLOCK node created here in `poplevel' is important
 	 (e.g. for proper debugging information) so if we created one
 	 earlier, mark it as "used".  */
       if (block)
 	TREE_USED (block) = 1;
-      block = poplevel (keep, reverse, real_functionbody);
+      block = poplevel (keep, reverse, functionbody);
     }
 
   /* Each and every BLOCK node created here in `poplevel' is important
@@ -6874,12 +6859,17 @@ start_decl_1 (decl)
   if (type == error_mark_node)
     return;
 
-  /* If this type of object needs a cleanup, and control may
-     jump past it, make a new binding level so that it is cleaned
-     up only when it is initialized first.  */
+  /* If this type of object needs a cleanup, but we're not allowed to
+     add any more objects with cleanups to the current scope, create a
+     new binding level.  */
   if (TYPE_NEEDS_DESTRUCTOR (type)
       && current_binding_level->more_cleanups_ok == 0)
-    pushlevel_temporary (1);
+    {
+      keep_next_level (2);
+      pushlevel (1);
+      clear_last_expr ();
+      add_scope_stmt (/*begin_p=*/1, /*partial_p=*/1);
+    }
 
   if (initialized)
     /* Is it valid for this decl to have an initializer at all?
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index 4c91e168232133610691d1f47cecb7f95dbb8181..d015719c73bced9c2dc799d7fdfda2fbf000b008 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -1248,6 +1248,43 @@ setup_vtbl_ptr ()
   vtbls_set_up_p = 1;
 }
 
+/* Add a scope-statement to the statement-tree.  BEGIN_P indicates
+   whether this statements opens or closes a scope.  PARTIAL_P is true
+   for a partial scope, i.e, the scope that begins after a label when
+   an object that needs a cleanup is created.  */
+
+void
+add_scope_stmt (begin_p, partial_p)
+     int begin_p;
+     int partial_p;
+{
+  tree ss;
+
+  /* Build the statement.  */
+  ss = build_min_nt (SCOPE_STMT);
+  SCOPE_BEGIN_P (ss) = begin_p;
+  SCOPE_PARTIAL_P (ss) = partial_p;
+
+  /* If we're finishing a scope, figure out whether the scope was
+     really necessary.  */
+  if (!begin_p)
+    {
+      SCOPE_NULLIFIED_P (ss) = !kept_level_p ();
+      SCOPE_NULLIFIED_P (TREE_VALUE (current_scope_stmt_stack))
+	= SCOPE_NULLIFIED_P (ss);
+    }
+
+  /* Keep the scope stack up to date.  */
+  if (begin_p)
+    current_scope_stmt_stack 
+      = tree_cons (NULL_TREE, ss, current_scope_stmt_stack);
+  else
+    current_scope_stmt_stack = TREE_CHAIN (current_scope_stmt_stack);
+
+  /* Add the new statement to the statement-tree.  */
+  add_tree (ss);
+}
+
 /* Begin a new scope.  */
 
 void
@@ -1266,13 +1303,7 @@ do_pushlevel ()
 	  && !current_function->x_whole_function_mode_p)
 	expand_start_bindings (0);
       else if (building_stmt_tree () && !processing_template_decl)
-	{
-	  tree ss = build_min_nt (SCOPE_STMT);
-	  SCOPE_BEGIN_P (ss) = 1;
-	  add_tree (ss);
-	  current_scope_stmt_stack 
-	    = tree_cons (NULL_TREE, ss, current_scope_stmt_stack);
-	}
+	add_scope_stmt (/*begin_p=*/1, /*partial_p=*/0);
     }
 }
 
@@ -1290,12 +1321,7 @@ do_poplevel ()
 	expand_end_bindings (getdecls (), kept_level_p (), 0);
       else if (building_stmt_tree () && !processing_template_decl)
 	{
-	  tree ss = build_min_nt (SCOPE_STMT);
-	  SCOPE_NULLIFIED_P (ss) = !kept_level_p ();
-	  SCOPE_NULLIFIED_P (TREE_VALUE (current_scope_stmt_stack))
-	    = SCOPE_NULLIFIED_P (ss);
-	  add_tree (ss);
-	  current_scope_stmt_stack = TREE_CHAIN (current_scope_stmt_stack);
+	  add_scope_stmt (/*begin_p=*/0, /*partial_p=*/0);
 
 	  /* When not in function-at-a-time mode, expand_end_bindings
 	     will warn about unused variables.  But, in
@@ -2455,7 +2481,8 @@ expand_stmt (t)
 	  if (SCOPE_BEGIN_P (t))
 	    expand_start_bindings (2 * SCOPE_NULLIFIED_P (t));
 	  else if (SCOPE_END_P (t))
-	    expand_end_bindings (NULL_TREE, !SCOPE_NULLIFIED_P (t), 0);
+	    expand_end_bindings (NULL_TREE, !SCOPE_NULLIFIED_P (t), 
+				 SCOPE_PARTIAL_P (t));
 	  break;
 
 	case RETURN_INIT:
diff --git a/gcc/testsuite/g++.old-deja/g++.other/debug5.C b/gcc/testsuite/g++.old-deja/g++.other/debug5.C
new file mode 100644
index 0000000000000000000000000000000000000000..bf885347b9ea777124903b46ebae6842fbdca553
--- /dev/null
+++ b/gcc/testsuite/g++.old-deja/g++.other/debug5.C
@@ -0,0 +1,15 @@
+// Build don't link:
+// Special g++ Options: -g
+// Origin: Mark Mitchell <mark@codesourcery.com>
+
+struct S
+{
+  ~S ();
+};
+
+void f ()
+{
+ t:
+  S s3;
+}
+
diff --git a/gcc/testsuite/g++.old-deja/g++.other/goto1.C b/gcc/testsuite/g++.old-deja/g++.other/goto1.C
new file mode 100644
index 0000000000000000000000000000000000000000..77da8e58b90bc28cd2874d46d6d9332e5bd934ed
--- /dev/null
+++ b/gcc/testsuite/g++.old-deja/g++.other/goto1.C
@@ -0,0 +1,21 @@
+// Build don't link:
+// Origin: Mark Mitchell <mark@codesourcery.com>
+
+struct S
+{
+  S ();
+  ~S ();
+};
+
+void f ()
+{
+  {
+    S s1;
+  
+  t:
+    S s2;
+    ;
+  }
+
+  goto t; // ERROR - jump avoids initialization of `s1'
+}