C++ PATCH: PR 13243 and PR 12573

Mark Mitchell mark@codesourcery.com
Mon Dec 15 16:57:00 GMT 2003


These PRs both had examples of expressions that were not
constant-expressions being used as template-arguments.  Some of us got
fooled into thinking we should fix value_dependent_expression_p, but
the real problem was that we were not correctly flagging these as
invalid template arguments.

The standard is not perfectly clear on what is permitted in an
integral constant-expression, and it has a partial listk of what is
forbidden, which confused me.  However, things like "[...]" and "->"
clearly should not be permitted, and the EDG front end rejects these
cases as well.

Tested on i686-pc-linux-gnu, applied on the mainline.

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


2003-12-15  Mark Mitchell  <mark@codesourcery.com>

	PR c++/13243
	PR c++/12573
	* parser.c (cp_parser_postfix_expression): Tighten handling of
	integral constant expressions.
	(cp_parser_unary_expression): Likewise.
	* pt.c (value_dependent_expression_p): Remove handling for
	COMPONENT_REFs.

2003-12-15  Mark Mitchell  <mark@codesourcery.com>

	PR c++/13243
	PR c++/12573
	* g++.dg/template/crash14.C: New test.
	* g++.dg/template/dependent-expr3.C: Add dg-error markers.

Index: cp/parser.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/parser.c,v
retrieving revision 1.131
diff -c -5 -p -r1.131 parser.c
*** cp/parser.c	15 Dec 2003 06:28:15 -0000	1.131
--- cp/parser.c	15 Dec 2003 16:52:57 -0000
*************** cp_parser_postfix_expression (cp_parser 
*** 3635,3644 ****
--- 3637,3655 ----
  
  	    /* Build the ARRAY_REF.  */
  	    postfix_expression 
  	      = grok_array_decl (postfix_expression, index);
  	    idk = CP_ID_KIND_NONE;
+ 	    /* Array references are not permitted in
+ 	       constant-expressions.  */
+ 	    if (parser->constant_expression_p)
+ 	      {
+ 		if (!parser->allow_non_constant_expression_p)
+ 		  postfix_expression 
+ 		    = cp_parser_non_constant_expression ("an array reference");
+ 		parser->non_constant_expression_p = true;
+ 	      }
  	  }
  	  break;
  
  	case CPP_OPEN_PAREN:
  	  /* postfix-expression ( expression-list [opt] ) */
*************** cp_parser_postfix_expression (cp_parser 
*** 3656,3666 ****
  	    /* Function calls are not permitted in
  	       constant-expressions.  */
  	    if (parser->constant_expression_p)
  	      {
  		if (!parser->allow_non_constant_expression_p)
! 		  return cp_parser_non_constant_expression ("a function call");
  		parser->non_constant_expression_p = true;
  	      }
  
  	    koenig_p = false;
  	    if (idk == CP_ID_KIND_UNQUALIFIED)
--- 3667,3681 ----
  	    /* Function calls are not permitted in
  	       constant-expressions.  */
  	    if (parser->constant_expression_p)
  	      {
  		if (!parser->allow_non_constant_expression_p)
! 		  {
! 		    postfix_expression 
! 		      = cp_parser_non_constant_expression ("a function call");
! 		    break;
! 		  }
  		parser->non_constant_expression_p = true;
  	      }
  
  	    koenig_p = false;
  	    if (idk == CP_ID_KIND_UNQUALIFIED)
*************** cp_parser_postfix_expression (cp_parser 
*** 3735,3744 ****
--- 3750,3760 ----
  	  {
  	    tree name;
  	    bool dependent_p;
  	    bool template_p;
  	    tree scope = NULL_TREE;
+ 	    enum cpp_ttype token_type = token->type;
  
  	    /* If this is a `->' operator, dereference the pointer.  */
  	    if (token->type == CPP_DEREF)
  	      postfix_expression = build_x_arrow (postfix_expression);
  	    /* Check to see whether or not the expression is
*************** cp_parser_postfix_expression (cp_parser 
*** 3837,3882 ****
  
  	    /* We no longer need to look up names in the scope of the
  	       object on the left-hand side of the `.' or `->'
  	       operator.  */
  	    parser->context->object_type = NULL_TREE;
  	  }
  	  break;
  
  	case CPP_PLUS_PLUS:
  	  /* postfix-expression ++  */
  	  /* Consume the `++' token.  */
  	  cp_lexer_consume_token (parser->lexer);
  	  /* Increments may not appear in constant-expressions.  */
  	  if (parser->constant_expression_p)
  	    {
  	      if (!parser->allow_non_constant_expression_p)
! 		return cp_parser_non_constant_expression ("an increment");
  	      parser->non_constant_expression_p = true;
  	    }
- 	  /* Generate a representation for the complete expression.  */
- 	  postfix_expression 
- 	    = finish_increment_expr (postfix_expression, 
- 				     POSTINCREMENT_EXPR);
  	  idk = CP_ID_KIND_NONE;
  	  break;
  
  	case CPP_MINUS_MINUS:
  	  /* postfix-expression -- */
  	  /* Consume the `--' token.  */
  	  cp_lexer_consume_token (parser->lexer);
  	  /* Decrements may not appear in constant-expressions.  */
  	  if (parser->constant_expression_p)
  	    {
  	      if (!parser->allow_non_constant_expression_p)
! 		return cp_parser_non_constant_expression ("a decrement");
  	      parser->non_constant_expression_p = true;
  	    }
- 	  /* Generate a representation for the complete expression.  */
- 	  postfix_expression 
- 	    = finish_increment_expr (postfix_expression, 
- 				     POSTDECREMENT_EXPR);
  	  idk = CP_ID_KIND_NONE;
  	  break;
  
  	default:
  	  return postfix_expression;
--- 3853,3909 ----
  
  	    /* We no longer need to look up names in the scope of the
  	       object on the left-hand side of the `.' or `->'
  	       operator.  */
  	    parser->context->object_type = NULL_TREE;
+ 	    /* These operators may not appear in constant-expressions.  */
+ 	    if (parser->constant_expression_p)
+ 	      {
+ 		if (!parser->allow_non_constant_expression_p)
+ 		  postfix_expression 
+ 		    = (cp_parser_non_constant_expression 
+ 		       (token_type == CPP_DEREF ? "'->'" : "`.'"));
+ 		parser->non_constant_expression_p = true;
+ 	      }
  	  }
  	  break;
  
  	case CPP_PLUS_PLUS:
  	  /* postfix-expression ++  */
  	  /* Consume the `++' token.  */
  	  cp_lexer_consume_token (parser->lexer);
+ 	  /* Generate a representation for the complete expression.  */
+ 	  postfix_expression 
+ 	    = finish_increment_expr (postfix_expression, 
+ 				     POSTINCREMENT_EXPR);
  	  /* Increments may not appear in constant-expressions.  */
  	  if (parser->constant_expression_p)
  	    {
  	      if (!parser->allow_non_constant_expression_p)
! 		postfix_expression 
! 		  = cp_parser_non_constant_expression ("an increment");
  	      parser->non_constant_expression_p = true;
  	    }
  	  idk = CP_ID_KIND_NONE;
  	  break;
  
  	case CPP_MINUS_MINUS:
  	  /* postfix-expression -- */
  	  /* Consume the `--' token.  */
  	  cp_lexer_consume_token (parser->lexer);
+ 	  /* Generate a representation for the complete expression.  */
+ 	  postfix_expression 
+ 	    = finish_increment_expr (postfix_expression, 
+ 				     POSTDECREMENT_EXPR);
  	  /* Decrements may not appear in constant-expressions.  */
  	  if (parser->constant_expression_p)
  	    {
  	      if (!parser->allow_non_constant_expression_p)
! 		postfix_expression 
! 		  = cp_parser_non_constant_expression ("a decrement");
  	      parser->non_constant_expression_p = true;
  	    }
  	  idk = CP_ID_KIND_NONE;
  	  break;
  
  	default:
  	  return postfix_expression;
*************** cp_parser_unary_expression (cp_parser *p
*** 4215,4260 ****
  	}
      }
    if (unary_operator != ERROR_MARK)
      {
        tree cast_expression;
  
        /* Consume the operator token.  */
        token = cp_lexer_consume_token (parser->lexer);
        /* Parse the cast-expression.  */
        cast_expression 
  	= cp_parser_cast_expression (parser, unary_operator == ADDR_EXPR);
        /* Now, build an appropriate representation.  */
        switch (unary_operator)
  	{
  	case INDIRECT_REF:
! 	  return build_x_indirect_ref (cast_expression, "unary *");
! 	  
  	case ADDR_EXPR:
  	case BIT_NOT_EXPR:
! 	  return build_x_unary_op (unary_operator, cast_expression);
! 	  
  	case PREINCREMENT_EXPR:
  	case PREDECREMENT_EXPR:
! 	  if (parser->constant_expression_p)
! 	    {
! 	      if (!parser->allow_non_constant_expression_p)
! 		return cp_parser_non_constant_expression (PREINCREMENT_EXPR
! 							  ? "an increment"
! 							  : "a decrement");
! 	      parser->non_constant_expression_p = true;
! 	    }
  	  /* Fall through.  */
  	case CONVERT_EXPR:
  	case NEGATE_EXPR:
  	case TRUTH_NOT_EXPR:
! 	  return finish_unary_op_expr (unary_operator, cast_expression);
  
  	default:
  	  abort ();
- 	  return error_mark_node;
  	}
      }
  
    return cp_parser_postfix_expression (parser, address_p);
  }
  
--- 4242,4297 ----
  	}
      }
    if (unary_operator != ERROR_MARK)
      {
        tree cast_expression;
+       tree expression = error_mark_node;
+       const char *non_constant_p = NULL;
  
        /* Consume the operator token.  */
        token = cp_lexer_consume_token (parser->lexer);
        /* Parse the cast-expression.  */
        cast_expression 
  	= cp_parser_cast_expression (parser, unary_operator == ADDR_EXPR);
        /* Now, build an appropriate representation.  */
        switch (unary_operator)
  	{
  	case INDIRECT_REF:
! 	  non_constant_p = "`*'";
! 	  expression = build_x_indirect_ref (cast_expression, "unary *");
! 	  break;
! 
  	case ADDR_EXPR:
+ 	  non_constant_p = "`&'";
+ 	  /* Fall through.  */
  	case BIT_NOT_EXPR:
! 	  expression = build_x_unary_op (unary_operator, cast_expression);
! 	  break;
! 
  	case PREINCREMENT_EXPR:
  	case PREDECREMENT_EXPR:
! 	  non_constant_p = (unary_operator == PREINCREMENT_EXPR
! 			    ? "`++'" : "`--'");
  	  /* Fall through.  */
  	case CONVERT_EXPR:
  	case NEGATE_EXPR:
  	case TRUTH_NOT_EXPR:
! 	  expression = finish_unary_op_expr (unary_operator, cast_expression);
! 	  break;
  
  	default:
  	  abort ();
  	}
+ 
+       if (non_constant_p && parser->constant_expression_p)
+ 	{
+ 	  if (!parser->allow_non_constant_expression_p)
+ 	    return cp_parser_non_constant_expression (non_constant_p);
+ 	  parser->non_constant_expression_p = true;
+ 	}
+ 
+       return expression;
      }
  
    return cp_parser_postfix_expression (parser, address_p);
  }
  
Index: cp/pt.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/pt.c,v
retrieving revision 1.801
diff -c -5 -p -r1.801 pt.c
*** cp/pt.c	13 Dec 2003 04:28:50 -0000	1.801
--- cp/pt.c	15 Dec 2003 16:53:03 -0000
*************** value_dependent_expression_p (tree expre
*** 11712,11724 ****
  	return dependent_type_p (expression);
        return type_dependent_expression_p (expression);
      }
    if (TREE_CODE (expression) == SCOPE_REF)
      return dependent_scope_ref_p (expression, value_dependent_expression_p);
-   if (TREE_CODE (expression) == COMPONENT_REF)
-     return (value_dependent_expression_p (TREE_OPERAND (expression, 0))
- 	    || value_dependent_expression_p (TREE_OPERAND (expression, 1)));
    /* A constant expression is value-dependent if any subexpression is
       value-dependent.  */
    if (IS_EXPR_CODE_CLASS (TREE_CODE_CLASS (TREE_CODE (expression))))
      {
        switch (TREE_CODE_CLASS (TREE_CODE (expression)))
--- 11712,11721 ----
Index: testsuite/g++.dg/template/crash14.C
===================================================================
RCS file: testsuite/g++.dg/template/crash14.C
diff -N testsuite/g++.dg/template/crash14.C
*** /dev/null	1 Jan 1970 00:00:00 -0000
--- testsuite/g++.dg/template/crash14.C	15 Dec 2003 16:53:05 -0000
***************
*** 0 ****
--- 1,3 ----
+ template <int T> class foo { public: foo() { } class Z { };};
+ template <int I[2]> void dep7(foo<I[0]> *) { } // { dg-error "" }
+ 
Index: testsuite/g++.dg/template/dependent-expr3.C
===================================================================
RCS file: /cvs/gcc/gcc/gcc/testsuite/g++.dg/template/dependent-expr3.C,v
retrieving revision 1.1
diff -c -5 -p -r1.1 dependent-expr3.C
*** testsuite/g++.dg/template/dependent-expr3.C	2 Dec 2003 12:10:32 -0000	1.1
--- testsuite/g++.dg/template/dependent-expr3.C	15 Dec 2003 16:53:05 -0000
*************** template <bool> struct S;
*** 7,14 ****
  template <typename K> struct Y : K {
    int x;
  };
  
  template <class T> struct Z {
!   S< (bool)(&static_cast<Y<T> *>(0)->x == 0) >
!     s;
  };
--- 7,14 ----
  template <typename K> struct Y : K {
    int x;
  };
  
  template <class T> struct Z {
!   S< (bool)(&static_cast<Y<T> *>(0)->x == 0) > // { dg-error "" }
!   s; // { dg-error "" }
  };



More information about the Gcc-patches mailing list