This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

C++ PATCH: PR 13969


This patch fixes additional fallout from the uses_template_parms
changes.  There's some unfortunate complexity in the C++ standard that
requires preserving the syntactic form of expressions until template
instantiation, but never-the-less performing full semantic analysis on
them at template parse time.

Tested on x86_64-suse-linux-gnu, applied on the mainline and on the
3.4 branch.

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

2004-02-04  Mark Mitchell  <mark@codesourcery.com>

	PR c++/13969
	* g++.dg/template/static6.C: New test.

2004-02-04  Mark Mitchell  <mark@codesourcery.com>

	PR c++/13969
	* cp-tree.h (fold_non_dependent_expr): New function.
	* parser.c (cp_parser_fold_non_dependent_expr): Remove.
	(cp_parser_template_argument): Use fold_non_dependent_expr.
	(cp_parser_direct_declarator): Likewise.
	* pt.c (fold_non_dependent_expr): New function.
	(convert_nontype_argument): Use it.
	(tsubst_qualified_id): Simplify.
	(tsubst_copy_and_build): Likewise.

Index: cp/cp-tree.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/cp-tree.h,v
retrieving revision 1.946.4.3
diff -c -5 -p -r1.946.4.3 cp-tree.h
*** cp/cp-tree.h	2 Feb 2004 16:26:37 -0000	1.946.4.3
--- cp/cp-tree.h	4 Feb 2004 18:12:29 -0000
*************** extern bool value_dependent_expression_p
*** 3925,3934 ****
--- 3925,3935 ----
  extern tree resolve_typename_type               (tree, bool);
  extern tree template_for_substitution           (tree);
  extern tree build_non_dependent_expr            (tree);
  extern tree build_non_dependent_args            (tree);
  extern bool reregister_specialization           (tree, tree, tree);
+ extern tree fold_non_dependent_expr             (tree);
  
  /* in repo.c */
  extern void repo_template_used (tree);
  extern void repo_template_instantiated (tree, bool);
  extern void init_repo (const char *);
Index: cp/parser.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/parser.c,v
retrieving revision 1.157.2.9
diff -c -5 -p -r1.157.2.9 parser.c
*** cp/parser.c	3 Feb 2004 20:04:32 -0000	1.157.2.9
--- cp/parser.c	4 Feb 2004 18:12:32 -0000
*************** static void cp_parser_late_parsing_defau
*** 1667,1678 ****
    (cp_parser *, tree);
  static tree cp_parser_sizeof_operand
    (cp_parser *, enum rid);
  static bool cp_parser_declares_only_class_p
    (cp_parser *);
- static tree cp_parser_fold_non_dependent_expr
-   (tree);
  static bool cp_parser_friend_p
    (tree);
  static cp_token *cp_parser_require
    (cp_parser *, enum cpp_ttype, const char *);
  static cp_token *cp_parser_require_keyword
--- 1667,1676 ----
*************** cp_parser_template_argument (cp_parser* 
*** 8409,8419 ****
    if (maybe_type_id)
      cp_parser_parse_tentatively (parser);
    argument = cp_parser_constant_expression (parser, 
  					    /*allow_non_constant_p=*/false,
  					    /*non_constant_p=*/NULL);
!   argument = cp_parser_fold_non_dependent_expr (argument);
    if (!maybe_type_id)
      return argument;
    if (!cp_parser_next_token_ends_template_argument_p (parser))
      cp_parser_error (parser, "expected template-argument");
    if (cp_parser_parse_definitely (parser))
--- 8407,8417 ----
    if (maybe_type_id)
      cp_parser_parse_tentatively (parser);
    argument = cp_parser_constant_expression (parser, 
  					    /*allow_non_constant_p=*/false,
  					    /*non_constant_p=*/NULL);
!   argument = fold_non_dependent_expr (argument);
    if (!maybe_type_id)
      return argument;
    if (!cp_parser_next_token_ends_template_argument_p (parser))
      cp_parser_error (parser, "expected template-argument");
    if (cp_parser_parse_definitely (parser))
*************** cp_parser_direct_declarator (cp_parser* 
*** 10415,10425 ****
  	      bounds 
  		= cp_parser_constant_expression (parser,
  						 /*allow_non_constant=*/true,
  						 &non_constant_p);
  	      if (!non_constant_p)
! 		bounds = cp_parser_fold_non_dependent_expr (bounds);
  	    }
  	  else
  	    bounds = NULL_TREE;
  	  /* Look for the closing `]'.  */
  	  if (!cp_parser_require (parser, CPP_CLOSE_SQUARE, "`]'"))
--- 10413,10423 ----
  	      bounds 
  		= cp_parser_constant_expression (parser,
  						 /*allow_non_constant=*/true,
  						 &non_constant_p);
  	      if (!non_constant_p)
! 		bounds = fold_non_dependent_expr (bounds);
  	    }
  	  else
  	    bounds = NULL_TREE;
  	  /* Look for the closing `]'.  */
  	  if (!cp_parser_require (parser, CPP_CLOSE_SQUARE, "`]'"))
*************** cp_parser_declares_only_class_p (cp_pars
*** 14730,14770 ****
  {
    /* If the next token is a `;' or a `,' then there is no 
       declarator.  */
    return (cp_lexer_next_token_is (parser->lexer, CPP_SEMICOLON)
  	  || cp_lexer_next_token_is (parser->lexer, CPP_COMMA));
- }
- 
- /* Simplify EXPR if it is a non-dependent expression.  Returns the
-    (possibly simplified) expression.  */
- 
- static tree
- cp_parser_fold_non_dependent_expr (tree expr)
- {
-   /* If we're in a template, but EXPR isn't value dependent, simplify
-      it.  We're supposed to treat:
-      
-        template <typename T> void f(T[1 + 1]);
-        template <typename T> void f(T[2]);
- 		   
-      as two declarations of the same function, for example.  */
-   if (processing_template_decl
-       && !type_dependent_expression_p (expr)
-       && !value_dependent_expression_p (expr))
-     {
-       HOST_WIDE_INT saved_processing_template_decl;
- 
-       saved_processing_template_decl = processing_template_decl;
-       processing_template_decl = 0;
-       expr = tsubst_copy_and_build (expr,
- 				    /*args=*/NULL_TREE,
- 				    tf_error,
- 				    /*in_decl=*/NULL_TREE,
- 				    /*function_p=*/false);
-       processing_template_decl = saved_processing_template_decl;
-     }
-   return expr;
  }
  
  /* DECL_SPECIFIERS is the representation of a decl-specifier-seq.
     Returns TRUE iff `friend' appears among the DECL_SPECIFIERS.  */
  
--- 14728,14737 ----
Index: cp/pt.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/pt.c,v
retrieving revision 1.816.2.8
diff -c -5 -p -r1.816.2.8 pt.c
*** cp/pt.c	3 Feb 2004 16:12:30 -0000	1.816.2.8
--- cp/pt.c	4 Feb 2004 18:12:35 -0000
*************** redeclare_class_template (tree type, tre
*** 3097,3120 ****
  	   parameters for any members.  */
  	TREE_PURPOSE (TREE_VEC_ELT (parms, i)) = tmpl_default;
      }
  }
  
  /* Attempt to convert the non-type template parameter EXPR to the
     indicated TYPE.  If the conversion is successful, return the
     converted value.  If the conversion is unsuccessful, return
     NULL_TREE if we issued an error message, or error_mark_node if we
     did not.  We issue error messages for out-and-out bad template
     parameters, but not simply because the conversion failed, since we
!    might be just trying to do argument deduction.  By the time this
!    function is called, neither TYPE nor EXPR may make use of template
!    parameters.  */
  
  static tree
  convert_nontype_argument (tree type, tree expr)
  {
!   tree expr_type = TREE_TYPE (expr);
  
    /* A template-argument for a non-type, non-template
       template-parameter shall be one of:
  
       --an integral constant-expression of integral or enumeration
--- 3097,3160 ----
  	   parameters for any members.  */
  	TREE_PURPOSE (TREE_VEC_ELT (parms, i)) = tmpl_default;
      }
  }
  
+ /* Simplify EXPR if it is a non-dependent expression.  Returns the
+    (possibly simplified) expression.  */
+ 
+ tree
+ fold_non_dependent_expr (tree expr)
+ {
+   /* If we're in a template, but EXPR isn't value dependent, simplify
+      it.  We're supposed to treat:
+      
+        template <typename T> void f(T[1 + 1]);
+        template <typename T> void f(T[2]);
+ 		   
+      as two declarations of the same function, for example.  */
+   if (processing_template_decl
+       && !type_dependent_expression_p (expr)
+       && !value_dependent_expression_p (expr))
+     {
+       HOST_WIDE_INT saved_processing_template_decl;
+ 
+       saved_processing_template_decl = processing_template_decl;
+       processing_template_decl = 0;
+       expr = tsubst_copy_and_build (expr,
+ 				    /*args=*/NULL_TREE,
+ 				    tf_error,
+ 				    /*in_decl=*/NULL_TREE,
+ 				    /*function_p=*/false);
+       processing_template_decl = saved_processing_template_decl;
+     }
+   return expr;
+ }
+ 
  /* Attempt to convert the non-type template parameter EXPR to the
     indicated TYPE.  If the conversion is successful, return the
     converted value.  If the conversion is unsuccessful, return
     NULL_TREE if we issued an error message, or error_mark_node if we
     did not.  We issue error messages for out-and-out bad template
     parameters, but not simply because the conversion failed, since we
!    might be just trying to do argument deduction.  Both TYPE and EXPR
!    must be non-dependent.  */
  
  static tree
  convert_nontype_argument (tree type, tree expr)
  {
!   tree expr_type;
! 
!   /* If we are in a template, EXPR may be non-dependent, but still
!      have a syntactic, rather than semantic, form.  For example, EXPR
!      might be a SCOPE_REF, rather than the VAR_DECL to which the
!      SCOPE_REF refers.  Preserving the qualifying scope is necessary
!      so that access checking can be performed when the template is
!      instantiated -- but here we need the resolved form so that we can
!      convert the argument.  */
!   expr = fold_non_dependent_expr (expr);
!   expr_type = TREE_TYPE (expr);
  
    /* A template-argument for a non-type, non-template
       template-parameter shall be one of:
  
       --an integral constant-expression of integral or enumeration
*************** convert_nontype_argument (tree type, tre
*** 3134,3149 ****
       array; or
       
       --a pointer to member expressed as described in _expr.unary.op_.  */
  
    /* An integral constant-expression can include const variables or
!      enumerators.  Simplify things by folding them to their values,
       unless we're about to bind the declaration to a reference
       parameter.  */
!   if (INTEGRAL_TYPE_P (expr_type)
!       && TREE_CODE (type) != REFERENCE_TYPE)
!     expr = decl_constant_value (expr);
  
    if (is_overloaded_fn (expr))
      /* OK for now.  We'll check that it has external linkage later.
         Check this first since if expr_type is the unknown_type_node
         we would otherwise complain below.  */
--- 3174,3208 ----
       array; or
       
       --a pointer to member expressed as described in _expr.unary.op_.  */
  
    /* An integral constant-expression can include const variables or
! .     enumerators.  Simplify things by folding them to their values,
       unless we're about to bind the declaration to a reference
       parameter.  */
!   if (INTEGRAL_TYPE_P (expr_type) && TREE_CODE (type) != REFERENCE_TYPE)
!     while (true) 
!       {
! 	tree const_expr = decl_constant_value (expr);
! 	/* In a template, the initializer for a VAR_DECL may not be
! 	   marked as TREE_CONSTANT, in which case decl_constant_value
! 	   will not return the initializer.  Handle that special case
! 	   here.  */
! 	if (expr == const_expr
! 	    && TREE_CODE (expr) == VAR_DECL
! 	    && DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (expr)
! 	    && CP_TYPE_CONST_NON_VOLATILE_P (TREE_TYPE (expr))
! 	    /* DECL_INITIAL can be NULL if we are processing a
! 	       variable initialized to an expression involving itself.
! 	       We know it is initialized to a constant -- but not what
! 	       constant, yet.  */
! 	    && DECL_INITIAL (expr))
! 	  const_expr = DECL_INITIAL (expr);
! 	if (expr == const_expr)
! 	  break;
! 	expr = fold_non_dependent_expr (const_expr);
!       }
  
    if (is_overloaded_fn (expr))
      /* OK for now.  We'll check that it has external linkage later.
         Check this first since if expr_type is the unknown_type_node
         we would otherwise complain below.  */
*************** tsubst_qualified_id (tree qualified_id, 
*** 7277,7291 ****
      check_accessibility_of_qualified_id (expr, /*object_type=*/NULL_TREE,
  					 scope);
    
    /* Remember that there was a reference to this entity.  */
    if (DECL_P (expr))
!     {
!       mark_used (expr);
!       if (!args && TREE_CODE (expr) == VAR_DECL)
! 	expr = DECL_INITIAL (expr);
!     }
  
    if (is_template)
      expr = lookup_template_function (expr, template_args);
  
    if (expr == error_mark_node && complain & tf_error)
--- 7336,7346 ----
      check_accessibility_of_qualified_id (expr, /*object_type=*/NULL_TREE,
  					 scope);
    
    /* Remember that there was a reference to this entity.  */
    if (DECL_P (expr))
!     mark_used (expr);
  
    if (is_template)
      expr = lookup_template_function (expr, template_args);
  
    if (expr == error_mark_node && complain & tf_error)
*************** tsubst_copy_and_build (tree t, 
*** 8483,8497 ****
        return convert_from_reference (tsubst_copy (t, args, complain, in_decl));
  
      case VAR_DECL:
        if (args)
  	t = tsubst_copy (t, args, complain, in_decl);
-       else
- 	/* If there are no ARGS, then we are evaluating a
- 	   non-dependent expression.  If the expression is
- 	   non-dependent, the variable must be a constant.  */
- 	t = DECL_INITIAL (t);
        return convert_from_reference (t);
  
      case VA_ARG_EXPR:
        return build_x_va_arg (RECUR (TREE_OPERAND (t, 0)),
  			     tsubst_copy (TREE_TYPE (t), args, complain, 
--- 8538,8547 ----
Index: testsuite/g++.dg/template/static6.C
===================================================================
RCS file: testsuite/g++.dg/template/static6.C
diff -N testsuite/g++.dg/template/static6.C
*** /dev/null	1 Jan 1970 00:00:00 -0000
--- testsuite/g++.dg/template/static6.C	4 Feb 2004 18:12:36 -0000
***************
*** 0 ****
--- 1,14 ----
+ // PR c++/13969
+ 
+ struct B { 
+   static const int N=10; 
+ }; 
+  
+ template <int> struct X {}; 
+  
+ template <typename> struct S { 
+   static const int N = B::N; 
+   X<N> x; 
+ }; 
+  
+ template class S<float>; 


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]