PATCH: PRs 22464, 22180, 23694, 23307, 22352, 22405

Mark Mitchell mark@codesourcery.com
Thu Oct 13 08:39:00 GMT 2005


This patch fixes some ICE regressions in the C++ front end:

PR 22464: We were getting confused when a member function of a local
class, nested within a member function of a template class, referred
to a parameter of the containing function.  That's not legal -- but we
weren't issuing the diagnostic at template-parse time.  By doing it at
that point, we avoid the crash.  (There's no problem with
multiple diagnostics at declaration and instantiation time because we
use error_mark_node to represent the erroneous expression.) 

PR 22180: "T::~T()" is not a valid call to a destructor, if "T" is a
template type parameter.  (You can say "this->T::~T()", but that's
different.)  We weren't considering that case, and ICEd.  (I also
noticed we weren't printing destructor names correctly in
build_new_method_call; fixed that.)

PR 23694: For some reason, G++ historically used void_type_node in
some places where it meant error_mark_node.  That's a recipe for ICEs;
this patch fixes one such place.

PR 23307: We were trying to cope with template declarations of static
data members.  Those aren't valid, and by issuing the error sooner we
avoid the ICE.

PR 22352: Template parameters for a member template in a template
class may still be dependent, even after substituting for parametmers
in the contaiing class, so we need to make sure
processing_template_decl is set, thereby making our dependency
predicates work.

PR 22405: Minor logic bug; the author of the code forgot that the
third expression in a for loop is executed before the second.

Tested on x86_64-unknown-linux-gnu.

--
Mark Mitchell
CodeSourcery, LLC
mark@codesourcery.com

2005-10-13  Mark Mitchell  <mark@codesourcery.com>

	PR c++/22464
	* semantics.c (finish_id_expression): Issue errors about uses of
	local variables in containing functions even in templates.

	PR c++/22180
	* call.c (build_new_method_call): Correct pretty-printing of
	destructor names.
	* pt.c (tsubst_qualified_id): Recognize invalid uses of "~T" as an
	identifier. 

	PR c++/23694
	* decl.c (start_method): Return error_mark_node for errors.

	PR c++/23307
	* pt.c (push_template_decl_real): Complain about attempts to
	declare template variables.

	PR c++/22352
	* pt.c (tsubst_template_parms): Set processing_template_decl while
	processing the parameters.
	(tsubst_decl): Set processing_template_decl when substituting into
	a TEMPLATE_DECL.

	PR c++/22405
	* pt.c (most_specialized_instantiation): Robustify.

2005-10-13  Mark Mitchell  <mark@codesourcery.com>

	PR c++/22464
	* g++.dg/template/crash/41.C: New test.

	PR c++/22180
	* g++.dg/template/crash40.C: New test.

	PR c++/23694
	* g++.dg/parse/friend5.C: New test.
	
	PR c++/23307
	* g++.dg/template/crash38.C: New test.
	
	PR c++/22352
	* g++.dg/template/friend38.C: New test.
	
	PR c++/22405
	* g++.dg/template/crash39.C: New test.
	
Index: gcc/cp/call.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/call.c,v
retrieving revision 1.556
diff -c -5 -p -r1.556 call.c
*** gcc/cp/call.c	11 Oct 2005 20:58:44 -0000	1.556
--- gcc/cp/call.c	13 Oct 2005 07:50:38 -0000
*************** build_new_method_call (tree instance, tr
*** 5341,5350 ****
--- 5341,5351 ----
    if (DECL_DESTRUCTOR_P (fn))
      {
        tree type = build_pointer_type (basetype);
        if (!same_type_p (type, TREE_TYPE (instance_ptr)))
  	instance_ptr = build_nop (type, instance_ptr);
+       name = complete_dtor_identifier;
      }
  
    class_type = (conversion_path ? BINFO_TYPE (conversion_path) : NULL_TREE);
    mem_args = tree_cons (NULL_TREE, instance_ptr, args);
  
Index: gcc/cp/decl.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/decl.c,v
retrieving revision 1.1431
diff -c -5 -p -r1.1431 decl.c
*** gcc/cp/decl.c	10 Oct 2005 14:41:49 -0000	1.1431
--- gcc/cp/decl.c	13 Oct 2005 07:50:40 -0000
*************** start_method (cp_decl_specifier_seq *dec
*** 10989,10999 ****
      {
        if (DECL_CONTEXT (fndecl)
  	  && TREE_CODE( DECL_CONTEXT (fndecl)) != NAMESPACE_DECL)
  	error ("%qD is already defined in class %qT", fndecl,
  	       DECL_CONTEXT (fndecl));
!       return void_type_node;
      }
  
    check_template_shadow (fndecl);
  
    DECL_DECLARED_INLINE_P (fndecl) = 1;
--- 10989,10999 ----
      {
        if (DECL_CONTEXT (fndecl)
  	  && TREE_CODE( DECL_CONTEXT (fndecl)) != NAMESPACE_DECL)
  	error ("%qD is already defined in class %qT", fndecl,
  	       DECL_CONTEXT (fndecl));
!       return error_mark_node;
      }
  
    check_template_shadow (fndecl);
  
    DECL_DECLARED_INLINE_P (fndecl) = 1;
Index: gcc/cp/pt.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/pt.c,v
retrieving revision 1.1043
diff -c -5 -p -r1.1043 pt.c
*** gcc/cp/pt.c	11 Oct 2005 06:26:04 -0000	1.1043
--- gcc/cp/pt.c	13 Oct 2005 07:50:41 -0000
*************** push_template_decl_real (tree decl, bool
*** 2996,3008 ****
  		 have two or more parameters.  */
  	      error ("invalid template declaration of %qD", decl);
  	      return decl;
  	    }
  	}
!       else if ((DECL_IMPLICIT_TYPEDEF_P (decl)
! 		&& CLASS_TYPE_P (TREE_TYPE (decl)))
! 	       || (TREE_CODE (decl) == VAR_DECL && ctx && CLASS_TYPE_P (ctx)))
  	/* OK */;
        else
  	{
  	  error ("template declaration of %q#D", decl);
  	  return error_mark_node;
--- 2996,3007 ----
  		 have two or more parameters.  */
  	      error ("invalid template declaration of %qD", decl);
  	      return decl;
  	    }
  	}
!       else if (DECL_IMPLICIT_TYPEDEF_P (decl)
! 	       && CLASS_TYPE_P (TREE_TYPE (decl)))
  	/* OK */;
        else
  	{
  	  error ("template declaration of %q#D", decl);
  	  return error_mark_node;
*************** static tree
*** 6000,6009 ****
--- 5999,6014 ----
  tsubst_template_parms (tree parms, tree args, tsubst_flags_t complain)
  {
    tree r = NULL_TREE;
    tree* new_parms;
  
+   /* When substituting into a template, we must set
+      PROCESSING_TEMPLATE_DECL as the template parameters may be
+      dependent if they are based on one-another, and the dependency
+      predicates are short-circuit outside of templates.  */
+   ++processing_template_decl;
+ 
    for (new_parms = &r;
         TMPL_PARMS_DEPTH (parms) > TMPL_ARGS_DEPTH (args);
         new_parms = &(TREE_CHAIN (*new_parms)),
  	 parms = TREE_CHAIN (parms))
      {
*************** tsubst_template_parms (tree parms, tree 
*** 6032,6041 ****
--- 6037,6048 ----
  	tree_cons (size_int (TMPL_PARMS_DEPTH (parms)
  			     - TMPL_ARGS_DEPTH (args)),
  		   new_vec, NULL_TREE);
      }
  
+   --processing_template_decl;
+ 
    return r;
  }
  
  /* Substitute the ARGS into the indicated aggregate (or enumeration)
     type T.  If T is not an aggregate or enumeration type, it is
*************** tsubst_decl (tree t, tree args, tsubst_f
*** 6239,6250 ****
--- 6246,6263 ----
  	   full args contain the tsubst'd args for the context,
  	   plus the innermost args from the template decl.  */
  	tmpl_args = DECL_CLASS_TEMPLATE_P (t)
  	  ? CLASSTYPE_TI_ARGS (TREE_TYPE (t))
  	  : DECL_TI_ARGS (DECL_TEMPLATE_RESULT (t));
+ 	/* Because this is a template, the arguments will still be
+ 	   dependent, even after substitution.  If
+ 	   PROCESSING_TEMPLATE_DECL is not set, the dependency
+ 	   predicates will short-circuit.  */
+ 	++processing_template_decl;
  	full_args = tsubst_template_args (tmpl_args, args,
  					  complain, in_decl);
+ 	--processing_template_decl;
  	if (full_args == error_mark_node)
  	  return error_mark_node;
  
  	/* tsubst_template_args doesn't copy the vector if
  	   nothing changed.  But, *something* should have
*************** tsubst_decl (tree t, tree args, tsubst_f
*** 6266,6302 ****
  	   than the old one.  */
  	r = copy_decl (t);
  	gcc_assert (DECL_LANG_SPECIFIC (r) != 0);
  	TREE_CHAIN (r) = NULL_TREE;
  
- 	DECL_CONTEXT (r)
- 	  = tsubst_aggr_type (DECL_CONTEXT (t), args,
- 			      complain, in_decl,
- 			      /*entering_scope=*/1);
  	DECL_TEMPLATE_INFO (r) = build_tree_list (t, args);
  
  	if (TREE_CODE (decl) == TYPE_DECL)
  	  {
! 	    tree new_type = tsubst (TREE_TYPE (t), args, complain, in_decl);
  	    if (new_type == error_mark_node)
  	      return error_mark_node;
  
  	    TREE_TYPE (r) = new_type;
  	    CLASSTYPE_TI_TEMPLATE (new_type) = r;
  	    DECL_TEMPLATE_RESULT (r) = TYPE_MAIN_DECL (new_type);
  	    DECL_TI_ARGS (r) = CLASSTYPE_TI_ARGS (new_type);
  	  }
  	else
  	  {
! 	    tree new_decl = tsubst (decl, args, complain, in_decl);
  	    if (new_decl == error_mark_node)
  	      return error_mark_node;
  
  	    DECL_TEMPLATE_RESULT (r) = new_decl;
  	    DECL_TI_TEMPLATE (new_decl) = r;
  	    TREE_TYPE (r) = TREE_TYPE (new_decl);
  	    DECL_TI_ARGS (r) = DECL_TI_ARGS (new_decl);
  	  }
  
  	SET_DECL_IMPLICIT_INSTANTIATION (r);
  	DECL_TEMPLATE_INSTANTIATIONS (r) = NULL_TREE;
  	DECL_TEMPLATE_SPECIALIZATIONS (r) = NULL_TREE;
--- 6279,6319 ----
  	   than the old one.  */
  	r = copy_decl (t);
  	gcc_assert (DECL_LANG_SPECIFIC (r) != 0);
  	TREE_CHAIN (r) = NULL_TREE;
  
  	DECL_TEMPLATE_INFO (r) = build_tree_list (t, args);
  
  	if (TREE_CODE (decl) == TYPE_DECL)
  	  {
! 	    tree new_type;
! 	    ++processing_template_decl;
! 	    new_type = tsubst (TREE_TYPE (t), args, complain, in_decl);
! 	    --processing_template_decl; 
  	    if (new_type == error_mark_node)
  	      return error_mark_node;
  
  	    TREE_TYPE (r) = new_type;
  	    CLASSTYPE_TI_TEMPLATE (new_type) = r;
  	    DECL_TEMPLATE_RESULT (r) = TYPE_MAIN_DECL (new_type);
  	    DECL_TI_ARGS (r) = CLASSTYPE_TI_ARGS (new_type);
+ 	    DECL_CONTEXT (r) = TYPE_CONTEXT (new_type);
  	  }
  	else
  	  {
! 	    tree new_decl;
! 	    ++processing_template_decl;
! 	    new_decl = tsubst (decl, args, complain, in_decl);
! 	    --processing_template_decl;
  	    if (new_decl == error_mark_node)
  	      return error_mark_node;
  
  	    DECL_TEMPLATE_RESULT (r) = new_decl;
  	    DECL_TI_TEMPLATE (new_decl) = r;
  	    TREE_TYPE (r) = TREE_TYPE (new_decl);
  	    DECL_TI_ARGS (r) = DECL_TI_ARGS (new_decl);
+ 	    DECL_CONTEXT (r) = DECL_CONTEXT (new_decl); 
  	  }
  
  	SET_DECL_IMPLICIT_INSTANTIATION (r);
  	DECL_TEMPLATE_INSTANTIATIONS (r) = NULL_TREE;
  	DECL_TEMPLATE_SPECIALIZATIONS (r) = NULL_TREE;
*************** tsubst_qualified_id (tree qualified_id, 
*** 7658,7668 ****
    if (dependent_type_p (scope))
      return build_nt (SCOPE_REF, scope, expr);
  
    if (!BASELINK_P (name) && !DECL_P (expr))
      {
!       expr = lookup_qualified_name (scope, expr, /*is_type_p=*/0, false);
        if (TREE_CODE (TREE_CODE (expr) == TEMPLATE_DECL
  		     ? DECL_TEMPLATE_RESULT (expr) : expr) == TYPE_DECL)
  	{
  	  if (complain & tf_error)
  	    {
--- 7675,7690 ----
    if (dependent_type_p (scope))
      return build_nt (SCOPE_REF, scope, expr);
  
    if (!BASELINK_P (name) && !DECL_P (expr))
      {
!       if (TREE_CODE (expr) == BIT_NOT_EXPR)
! 	/* If this were actually a destructor call, it would have been
! 	   parsed as such by the parser.  */
! 	expr = error_mark_node;
!       else
! 	expr = lookup_qualified_name (scope, expr, /*is_type_p=*/0, false);
        if (TREE_CODE (TREE_CODE (expr) == TEMPLATE_DECL
  		     ? DECL_TEMPLATE_RESULT (expr) : expr) == TYPE_DECL)
  	{
  	  if (complain & tf_error)
  	    {
*************** most_specialized_instantiation (tree ins
*** 10782,10798 ****
        if (get_bindings (TREE_VALUE (fn),
  			DECL_TEMPLATE_RESULT (TREE_VALUE (champ)),
  			NULL_TREE, /*check_ret=*/false))
  	fate++;
  
!       if (fate != 1)
! 	{
! 	  if (!fate)
! 	    /* Equally specialized, move to next function.  If there
! 	       is no next function, nothing's most specialized.  */
! 	    fn = TREE_CHAIN (fn);
! 	  champ = fn;
  	}
      }
  
    if (champ)
      /* Now verify that champ is better than everything earlier in the
--- 10804,10822 ----
        if (get_bindings (TREE_VALUE (fn),
  			DECL_TEMPLATE_RESULT (TREE_VALUE (champ)),
  			NULL_TREE, /*check_ret=*/false))
  	fate++;
  
!       if (fate == -1)
! 	champ = fn;
!       else if (!fate)
! 	{
! 	  /* Equally specialized, move to next function.  If there
! 	     is no next function, nothing's most specialized.  */
! 	  fn = TREE_CHAIN (fn);
! 	  if (!fn)
! 	    break;
  	}
      }
  
    if (champ)
      /* Now verify that champ is better than everything earlier in the
Index: gcc/cp/semantics.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/semantics.c,v
retrieving revision 1.491
diff -c -5 -p -r1.491 semantics.c
*** gcc/cp/semantics.c	5 Oct 2005 12:17:13 -0000	1.491
--- gcc/cp/semantics.c	13 Oct 2005 07:50:41 -0000
*************** finish_id_expression (tree id_expression
*** 2457,2466 ****
--- 2457,2481 ----
  	 the current class so that we can check later to see if
  	 the meaning would have been different after the class
  	 was entirely defined.  */
        if (!scope && decl != error_mark_node)
  	maybe_note_name_used_in_class (id_expression, decl);
+ 
+       /* Disallow uses of local variables from containing functions.  */
+       if (TREE_CODE (decl) == VAR_DECL || TREE_CODE (decl) == PARM_DECL)
+ 	{
+ 	  tree context = decl_function_context (decl);
+ 	  if (context != NULL_TREE && context != current_function_decl
+ 	      && ! TREE_STATIC (decl))
+ 	    {
+ 	      error (TREE_CODE (decl) == VAR_DECL
+ 		     ? "use of %<auto%> variable from containing function"
+ 		     : "use of parameter from containing function");
+ 	      error ("  %q+#D declared here", decl);
+ 	      return error_mark_node;
+ 	    }
+ 	}
      }
  
    /* If we didn't find anything, or what we found was a type,
       then this wasn't really an id-expression.  */
    if (TREE_CODE (decl) == TEMPLATE_DECL
*************** finish_id_expression (tree id_expression
*** 2728,2754 ****
  	      return finish_class_member_access_expr (decl, id_expression);
  	    }
  	}
        else
  	{
- 	  if (TREE_CODE (decl) == VAR_DECL
- 	      || TREE_CODE (decl) == PARM_DECL
- 	      || TREE_CODE (decl) == RESULT_DECL)
- 	    {
- 	      tree context = decl_function_context (decl);
- 
- 	      if (context != NULL_TREE && context != current_function_decl
- 		  && ! TREE_STATIC (decl))
- 		{
- 		  error (TREE_CODE (decl) == VAR_DECL
- 			 ? "use of %<auto%> variable from containing function"
- 			 : "use of parameter from containing function");
- 		  error ("  %q+#D declared here", decl);
- 		  return error_mark_node;
- 		}
- 	    }
- 
  	  if (DECL_P (decl) && DECL_NONLOCAL (decl)
  	      && DECL_CLASS_SCOPE_P (decl)
  	      && DECL_CONTEXT (decl) != current_class_type)
  	    {
  	      tree path;
--- 2743,2752 ----
Index: gcc/testsuite/g++.dg/parse/friend5.C
===================================================================
RCS file: gcc/testsuite/g++.dg/parse/friend5.C
diff -N gcc/testsuite/g++.dg/parse/friend5.C
*** /dev/null	1 Jan 1970 00:00:00 -0000
--- gcc/testsuite/g++.dg/parse/friend5.C	13 Oct 2005 07:50:42 -0000
***************
*** 0 ****
--- 1,7 ----
+ // PR c++/23694
+  
+ extern "C" struct A
+ {
+   friend void foo(int) {} // { dg-error "declaration" }
+   friend void foo() {} // { dg-error "foo" }
+ };
Index: gcc/testsuite/g++.dg/template/crash38.C
===================================================================
RCS file: gcc/testsuite/g++.dg/template/crash38.C
diff -N gcc/testsuite/g++.dg/template/crash38.C
*** /dev/null	1 Jan 1970 00:00:00 -0000
--- gcc/testsuite/g++.dg/template/crash38.C	13 Oct 2005 07:50:42 -0000
***************
*** 0 ****
--- 1,8 ----
+ // PR c++/23307
+ 
+ class A
+ {
+   template<class R>
+   static void f(X&); // { dg-error "" }
+   inline void A::f<void>(X&); // { dg-error "f|expected" }
+ };
Index: gcc/testsuite/g++.dg/template/crash39.C
===================================================================
RCS file: gcc/testsuite/g++.dg/template/crash39.C
diff -N gcc/testsuite/g++.dg/template/crash39.C
*** /dev/null	1 Jan 1970 00:00:00 -0000
--- gcc/testsuite/g++.dg/template/crash39.C	13 Oct 2005 07:50:42 -0000
***************
*** 0 ****
--- 1,11 ----
+ // PR c++/22405
+ 
+ template <typename T> void foo(T &arg) { // { dg-error "declared" }
+   arg+=1;
+ }
+ 
+ template <typename T> void foo(T &arg) { // { dg-error "redefinition" }
+   arg+=2;
+ }
+ 
+ template void foo(float &arg);
Index: gcc/testsuite/g++.dg/template/crash40.C
===================================================================
RCS file: gcc/testsuite/g++.dg/template/crash40.C
diff -N gcc/testsuite/g++.dg/template/crash40.C
*** /dev/null	1 Jan 1970 00:00:00 -0000
--- gcc/testsuite/g++.dg/template/crash40.C	13 Oct 2005 07:50:42 -0000
***************
*** 0 ****
--- 1,10 ----
+ // PR c++/22180
+ 
+ struct A {};
+ 
+ template<typename T> void foo()
+ {
+   T::~T(); // { dg-error "member" }
+ }
+ 
+ template void foo<A>(); // { dg-error "instantiated" }
Index: gcc/testsuite/g++.dg/template/crash41.C
===================================================================
RCS file: gcc/testsuite/g++.dg/template/crash41.C
diff -N gcc/testsuite/g++.dg/template/crash41.C
*** /dev/null	1 Jan 1970 00:00:00 -0000
--- gcc/testsuite/g++.dg/template/crash41.C	13 Oct 2005 07:50:42 -0000
***************
*** 0 ****
--- 1,18 ----
+ // PR c++/22464
+ 
+ template<typename T>
+ void do_something(const T* A) // { dg-error "declared" }
+ { 
+   struct helper_t{ 
+     helper_t() {  
+       A[0]; // { dg-error "use" }
+     }
+   } helper;
+ }
+ 
+ void sub1() {
+   double A[7];
+   do_something (A);
+ }
+ 
+   
Index: gcc/testsuite/g++.dg/template/friend38.C
===================================================================
RCS file: gcc/testsuite/g++.dg/template/friend38.C
diff -N gcc/testsuite/g++.dg/template/friend38.C
*** /dev/null	1 Jan 1970 00:00:00 -0000
--- gcc/testsuite/g++.dg/template/friend38.C	13 Oct 2005 07:50:42 -0000
***************
*** 0 ****
--- 1,12 ----
+ // PR c++/22352
+ 
+ template <class A>
+ class s
+ {
+   typedef int d;
+   template <class s, typename s::d>
+   friend class t;
+ };
+ 
+ s<int> t1;
+ 



More information about the Gcc-patches mailing list