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]

PR c++/14586


This patch fixes PR c++/14586, which is another case where we
mistakenly treated a non-constant expression as being constant.  The
PR is a tricky corner case: one might think that if the operands "x"
and "y" are integral constant expressions then "x op y" would also be
for choices of "op" like "+" -- but if "x" or "y" has enumeration type
then "op" might be an overloaded operator.

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

--
Mark Mitchell
CodeSourcery, LLC
(916) 791-8304
mark@codesourcery.com

2004-03-16  Mark Mitchell  <mark@codesourcery.com>

	PR c++/14586
	* cp-tree.h (build_new_op): Change prototype.
	(build_x_binary_op): Likewise.
	* call.c (build_new_op): Add overloaded_p parameter.
	* decl2.c (grok_array_decl): Adjust call to build_new_op.
	* parser.c (cp_parser_binary_expression): Note that uses of
	overloaded operators prevents an expression from being considered
	an integral constant.
	* pt.c (tsubst_copy_and_build): Adjust calls to build_new_op and/or
	build_x_binary_op.
	* semantics.c (finish_call_expr): Likewise.
	* typeck.c (rationalize_conditional_expr): Likewise.
	(build_x_indirect_ref): Likewise.
	(build_x_binary_op): Likewise.
	(build_x_unary_op): Likewise.
	(build_x_compound_expr): Likewise.
	(build_modify_expr): Likewise.
	* typeck2.c (build_x_arrow): Likewise.

2004-03-16  Mark Mitchell  <mark@codesourcery.com>

	PR c++/14586
	* g++.dg/parse/non-dependent3.C: New test.

Index: cp/call.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/call.c,v
retrieving revision 1.452.2.12
diff -c -5 -p -r1.452.2.12 call.c
*** cp/call.c	9 Mar 2004 18:26:34 -0000	1.452.2.12
--- cp/call.c	16 Mar 2004 21:30:30 -0000
*************** add_candidates (tree fns, tree args, 
*** 3369,3379 ****
        fns = OVL_NEXT (fns);
      }
  }
  
  tree
! build_new_op (enum tree_code code, int flags, tree arg1, tree arg2, tree arg3)
  {
    struct z_candidate *candidates = 0, *cand;
    tree arglist, fnname;
    tree args[3];
    enum tree_code code2 = NOP_EXPR;
--- 3369,3380 ----
        fns = OVL_NEXT (fns);
      }
  }
  
  tree
! build_new_op (enum tree_code code, int flags, tree arg1, tree arg2, tree arg3,
! 	      bool *overloaded_p)
  {
    struct z_candidate *candidates = 0, *cand;
    tree arglist, fnname;
    tree args[3];
    enum tree_code code2 = NOP_EXPR;
*************** build_new_op (enum tree_code code, int f
*** 3512,3522 ****
  			operator_name_info[code].name);
  	  if (code == POSTINCREMENT_EXPR)
  	    code = PREINCREMENT_EXPR;
  	  else
  	    code = PREDECREMENT_EXPR;	
! 	  return build_new_op (code, flags, arg1, NULL_TREE, NULL_TREE);
  	  
  	  /* The caller will deal with these.  */
  	case ADDR_EXPR:
  	case COMPOUND_EXPR:
  	case COMPONENT_REF:
--- 3513,3524 ----
  			operator_name_info[code].name);
  	  if (code == POSTINCREMENT_EXPR)
  	    code = PREINCREMENT_EXPR;
  	  else
  	    code = PREDECREMENT_EXPR;	
! 	  return build_new_op (code, flags, arg1, NULL_TREE, NULL_TREE,
! 			       overloaded_p);
  	  
  	  /* The caller will deal with these.  */
  	case ADDR_EXPR:
  	case COMPOUND_EXPR:
  	case COMPONENT_REF:
*************** build_new_op (enum tree_code code, int f
*** 3544,3553 ****
--- 3546,3558 ----
        return error_mark_node;
      }
  
    if (TREE_CODE (cand->fn) == FUNCTION_DECL)
      {
+       if (overloaded_p)
+ 	*overloaded_p = true;
+ 
        if (warn_synth
  	  && fnname == ansi_assopname (NOP_EXPR)
  	  && DECL_ARTIFICIAL (cand->fn)
  	  && candidates->next
  	  && ! candidates->next->next)
Index: cp/cp-tree.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/cp-tree.h,v
retrieving revision 1.946.4.9
diff -c -5 -p -r1.946.4.9 cp-tree.h
*** cp/cp-tree.h	10 Mar 2004 21:04:13 -0000	1.946.4.9
--- cp/cp-tree.h	16 Mar 2004 21:30:31 -0000
*************** extern tree type_decays_to (tree);
*** 3512,3522 ****
  extern tree build_user_type_conversion (tree, tree, int);
  extern tree build_new_function_call (tree, tree);
  extern tree build_operator_new_call (tree, tree, tree *, tree *);
  extern tree build_new_method_call (tree, tree, tree, tree, int);
  extern tree build_special_member_call (tree, tree, tree, tree, int);
! extern tree build_new_op (enum tree_code, int, tree, tree, tree);
  extern tree build_op_delete_call (enum tree_code, tree, tree, int, tree);
  extern bool can_convert (tree, tree);
  extern bool can_convert_arg (tree, tree, tree);
  extern bool can_convert_arg_bad (tree, tree, tree);
  extern bool enforce_access (tree, tree);
--- 3512,3522 ----
  extern tree build_user_type_conversion (tree, tree, int);
  extern tree build_new_function_call (tree, tree);
  extern tree build_operator_new_call (tree, tree, tree *, tree *);
  extern tree build_new_method_call (tree, tree, tree, tree, int);
  extern tree build_special_member_call (tree, tree, tree, tree, int);
! extern tree build_new_op (enum tree_code, int, tree, tree, tree, bool *);
  extern tree build_op_delete_call (enum tree_code, tree, tree, int, tree);
  extern bool can_convert (tree, tree);
  extern bool can_convert_arg (tree, tree, tree);
  extern bool can_convert_arg_bad (tree, tree, tree);
  extern bool enforce_access (tree, tree);
*************** extern tree finish_class_member_access_e
*** 4200,4210 ****
  extern tree build_x_indirect_ref		(tree, const char *);
  extern tree build_indirect_ref			(tree, const char *);
  extern tree build_array_ref			(tree, tree);
  extern tree get_member_function_from_ptrfunc	(tree *, tree);
  extern tree convert_arguments			(tree, tree, tree, int);
! extern tree build_x_binary_op			(enum tree_code, tree, tree);
  extern tree build_x_unary_op			(enum tree_code, tree);
  extern tree unary_complex_lvalue		(enum tree_code, tree);
  extern tree build_x_conditional_expr		(tree, tree, tree);
  extern tree build_x_compound_expr_from_list 	(tree, const char *);
  extern tree build_x_compound_expr		(tree, tree);
--- 4200,4211 ----
  extern tree build_x_indirect_ref		(tree, const char *);
  extern tree build_indirect_ref			(tree, const char *);
  extern tree build_array_ref			(tree, tree);
  extern tree get_member_function_from_ptrfunc	(tree *, tree);
  extern tree convert_arguments			(tree, tree, tree, int);
! extern tree build_x_binary_op			(enum tree_code, tree, tree, 
! 						 bool *);
  extern tree build_x_unary_op			(enum tree_code, tree);
  extern tree unary_complex_lvalue		(enum tree_code, tree);
  extern tree build_x_conditional_expr		(tree, tree, tree);
  extern tree build_x_compound_expr_from_list 	(tree, const char *);
  extern tree build_x_compound_expr		(tree, tree);
Index: cp/decl2.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/decl2.c,v
retrieving revision 1.695.4.4
diff -c -5 -p -r1.695.4.4 decl2.c
*** cp/decl2.c	1 Mar 2004 06:21:39 -0000	1.695.4.4
--- cp/decl2.c	16 Mar 2004 21:30:38 -0000
*************** grok_array_decl (tree array_expr, tree i
*** 378,388 ****
    type = non_reference (type);
  
    /* If they have an `operator[]', use that.  */
    if (IS_AGGR_TYPE (type) || IS_AGGR_TYPE (TREE_TYPE (index_exp)))
      expr = build_new_op (ARRAY_REF, LOOKUP_NORMAL,
! 			 array_expr, index_exp, NULL_TREE);
    else
      {
        tree p1, p2, i1, i2;
  
        /* Otherwise, create an ARRAY_REF for a pointer or array type.
--- 378,389 ----
    type = non_reference (type);
  
    /* If they have an `operator[]', use that.  */
    if (IS_AGGR_TYPE (type) || IS_AGGR_TYPE (TREE_TYPE (index_exp)))
      expr = build_new_op (ARRAY_REF, LOOKUP_NORMAL,
! 			 array_expr, index_exp, NULL_TREE,
! 			 /*overloaded_p=*/NULL);
    else
      {
        tree p1, p2, i1, i2;
  
        /* Otherwise, create an ARRAY_REF for a pointer or array type.
Index: cp/parser.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/parser.c,v
retrieving revision 1.157.2.21
diff -c -5 -p -r1.157.2.21 parser.c
*** cp/parser.c	13 Mar 2004 16:44:12 -0000	1.157.2.21
--- cp/parser.c	16 Mar 2004 21:30:44 -0000
*************** cp_parser_binary_expression (cp_parser* 
*** 13878,13893 ****
        for (map_node = token_tree_map; 
  	   map_node->token_type != CPP_EOF;
  	   ++map_node)
  	if (map_node->token_type == token->type)
  	  {
  	    /* Consume the operator token.  */
  	    cp_lexer_consume_token (parser->lexer);
  	    /* Parse the right-hand side of the expression.  */
  	    rhs = (*fn) (parser);
  	    /* Build the binary tree node.  */
! 	    lhs = build_x_binary_op (map_node->tree_type, lhs, rhs);
  	    break;
  	  }
  
        /* If the token wasn't one of the ones we want, we're done.  */
        if (map_node->token_type == CPP_EOF)
--- 13878,13907 ----
        for (map_node = token_tree_map; 
  	   map_node->token_type != CPP_EOF;
  	   ++map_node)
  	if (map_node->token_type == token->type)
  	  {
+ 	    /* Assume that an overloaded operator will not be used.  */
+ 	    bool overloaded_p = false;
+ 
  	    /* Consume the operator token.  */
  	    cp_lexer_consume_token (parser->lexer);
  	    /* Parse the right-hand side of the expression.  */
  	    rhs = (*fn) (parser);
  	    /* Build the binary tree node.  */
! 	    lhs = build_x_binary_op (map_node->tree_type, lhs, rhs, 
! 				     &overloaded_p);
! 	    /* If the binary operator required the use of an
! 	       overloaded operator, then this expression cannot be an
! 	       integral constant-expression.  An overloaded operator
! 	       can be used even if both operands are otherwise
! 	       permissible in an integral constant-expression if at
! 	       least one of the operands is of enumeration type.  */
! 	    if (overloaded_p
! 		&& (cp_parser_non_integral_constant_expression 
! 		    (parser, "calls to overloaded operators")))
! 	      lhs = error_mark_node;
  	    break;
  	  }
  
        /* If the token wasn't one of the ones we want, we're done.  */
        if (map_node->token_type == CPP_EOF)
Index: cp/pt.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/pt.c,v
retrieving revision 1.816.2.18
diff -c -5 -p -r1.816.2.18 pt.c
*** cp/pt.c	9 Mar 2004 15:41:36 -0000	1.816.2.18
--- cp/pt.c	16 Mar 2004 21:30:48 -0000
*************** tsubst_copy_and_build (tree t, 
*** 8266,8276 ****
      case MEMBER_REF:
      case DOTSTAR_EXPR:
        return build_x_binary_op
  	(TREE_CODE (t), 
  	 RECUR (TREE_OPERAND (t, 0)),
! 	 RECUR (TREE_OPERAND (t, 1)));
  
      case SCOPE_REF:
        return tsubst_qualified_id (t, args, complain, in_decl, /*done=*/true,
  				  /*address_p=*/false);
  
--- 8266,8277 ----
      case MEMBER_REF:
      case DOTSTAR_EXPR:
        return build_x_binary_op
  	(TREE_CODE (t), 
  	 RECUR (TREE_OPERAND (t, 0)),
! 	 RECUR (TREE_OPERAND (t, 1)),
! 	 /*overloaded_p=*/NULL);
  
      case SCOPE_REF:
        return tsubst_qualified_id (t, args, complain, in_decl, /*done=*/true,
  				  /*address_p=*/false);
  
Index: cp/semantics.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/semantics.c,v
retrieving revision 1.381.4.8
diff -c -5 -p -r1.381.4.8 semantics.c
*** cp/semantics.c	20 Feb 2004 09:03:29 -0000	1.381.4.8
--- cp/semantics.c	16 Mar 2004 21:30:50 -0000
*************** finish_call_expr (tree fn, tree args, bo
*** 1727,1737 ****
        TREE_SIDE_EFFECTS (result) = 1;
      }
    else if (CLASS_TYPE_P (TREE_TYPE (fn)))
      /* If the "function" is really an object of class type, it might
         have an overloaded `operator ()'.  */
!     result = build_new_op (CALL_EXPR, LOOKUP_NORMAL, fn, args, NULL_TREE);
    if (!result)
      /* A call where the function is unknown.  */
      result = build_function_call (fn, args);
  
    if (processing_template_decl)
--- 1727,1738 ----
        TREE_SIDE_EFFECTS (result) = 1;
      }
    else if (CLASS_TYPE_P (TREE_TYPE (fn)))
      /* If the "function" is really an object of class type, it might
         have an overloaded `operator ()'.  */
!     result = build_new_op (CALL_EXPR, LOOKUP_NORMAL, fn, args, NULL_TREE,
! 			   /*overloaded_p=*/NULL);
    if (!result)
      /* A call where the function is unknown.  */
      result = build_function_call (fn, args);
  
    if (processing_template_decl)
Index: cp/typeck.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/typeck.c,v
retrieving revision 1.519.2.9
diff -c -5 -p -r1.519.2.9 typeck.c
*** cp/typeck.c	2 Mar 2004 19:57:06 -0000	1.519.2.9
--- cp/typeck.c	16 Mar 2004 21:30:52 -0000
*************** rationalize_conditional_expr (enum tree_
*** 1491,1501 ****
      {
        return
  	build_conditional_expr (build_x_binary_op ((TREE_CODE (t) == MIN_EXPR
  						    ? LE_EXPR : GE_EXPR),
  						   TREE_OPERAND (t, 0),
! 						   TREE_OPERAND (t, 1)),
  			    build_unary_op (code, TREE_OPERAND (t, 0), 0),
  			    build_unary_op (code, TREE_OPERAND (t, 1), 0));
      }
  
    return
--- 1491,1502 ----
      {
        return
  	build_conditional_expr (build_x_binary_op ((TREE_CODE (t) == MIN_EXPR
  						    ? LE_EXPR : GE_EXPR),
  						   TREE_OPERAND (t, 0),
! 						   TREE_OPERAND (t, 1),
! 						   /*overloaded_p=*/NULL),
  			    build_unary_op (code, TREE_OPERAND (t, 0), 0),
  			    build_unary_op (code, TREE_OPERAND (t, 1), 0));
      }
  
    return
*************** build_x_indirect_ref (tree expr, const c
*** 2024,2034 ****
  	return build_min_nt (INDIRECT_REF, expr);
        expr = build_non_dependent_expr (expr);
      }
  
    rval = build_new_op (INDIRECT_REF, LOOKUP_NORMAL, expr, NULL_TREE,
! 		       NULL_TREE);
    if (!rval)
      rval = build_indirect_ref (expr, errorstring);
  
    if (processing_template_decl && rval != error_mark_node)
      return build_min_non_dep (INDIRECT_REF, rval, orig_expr);
--- 2025,2035 ----
  	return build_min_nt (INDIRECT_REF, expr);
        expr = build_non_dependent_expr (expr);
      }
  
    rval = build_new_op (INDIRECT_REF, LOOKUP_NORMAL, expr, NULL_TREE,
! 		       NULL_TREE, /*overloaded_p=*/NULL);
    if (!rval)
      rval = build_indirect_ref (expr, errorstring);
  
    if (processing_template_decl && rval != error_mark_node)
      return build_min_non_dep (INDIRECT_REF, rval, orig_expr);
*************** convert_arguments (tree typelist, tree v
*** 2652,2662 ****
  
  /* Build a binary-operation expression, after performing default
     conversions on the operands.  CODE is the kind of expression to build.  */
  
  tree
! build_x_binary_op (enum tree_code code, tree arg1, tree arg2)
  {
    tree orig_arg1;
    tree orig_arg2;
    tree expr;
  
--- 2653,2664 ----
  
  /* Build a binary-operation expression, after performing default
     conversions on the operands.  CODE is the kind of expression to build.  */
  
  tree
! build_x_binary_op (enum tree_code code, tree arg1, tree arg2, 
! 		   bool *overloaded_p)
  {
    tree orig_arg1;
    tree orig_arg2;
    tree expr;
  
*************** build_x_binary_op (enum tree_code code, 
*** 2673,2683 ****
      }
  
    if (code == DOTSTAR_EXPR)
      expr = build_m_component_ref (arg1, arg2);
    else
!     expr = build_new_op (code, LOOKUP_NORMAL, arg1, arg2, NULL_TREE);
  
    if (processing_template_decl && expr != error_mark_node)
      return build_min_non_dep (code, expr, orig_arg1, orig_arg2);
    
    return expr;
--- 2675,2686 ----
      }
  
    if (code == DOTSTAR_EXPR)
      expr = build_m_component_ref (arg1, arg2);
    else
!     expr = build_new_op (code, LOOKUP_NORMAL, arg1, arg2, NULL_TREE, 
! 			 overloaded_p);
  
    if (processing_template_decl && expr != error_mark_node)
      return build_min_non_dep (code, expr, orig_arg1, orig_arg2);
    
    return expr;
*************** build_x_unary_op (enum tree_code code, t
*** 3530,3540 ****
        && ((IS_AGGR_TYPE_CODE (TREE_CODE (TREE_TYPE (xarg)))
  	   && !COMPLETE_TYPE_P (TREE_TYPE (xarg)))
  	  || (TREE_CODE (xarg) == OFFSET_REF)))
      /* Don't look for a function.  */;
    else
!     exp = build_new_op (code, LOOKUP_NORMAL, xarg, NULL_TREE, NULL_TREE);
    if (!exp && code == ADDR_EXPR)
      {
        /*  A pointer to member-function can be formed only by saying
  	  &X::mf.  */
        if (!flag_ms_extensions && TREE_CODE (TREE_TYPE (xarg)) == METHOD_TYPE
--- 3533,3544 ----
        && ((IS_AGGR_TYPE_CODE (TREE_CODE (TREE_TYPE (xarg)))
  	   && !COMPLETE_TYPE_P (TREE_TYPE (xarg)))
  	  || (TREE_CODE (xarg) == OFFSET_REF)))
      /* Don't look for a function.  */;
    else
!     exp = build_new_op (code, LOOKUP_NORMAL, xarg, NULL_TREE, NULL_TREE,
! 			/*overloaded_p=*/NULL);
    if (!exp && code == ADDR_EXPR)
      {
        /*  A pointer to member-function can be formed only by saying
  	  &X::mf.  */
        if (!flag_ms_extensions && TREE_CODE (TREE_TYPE (xarg)) == METHOD_TYPE
*************** build_x_compound_expr (tree op1, tree op
*** 4370,4380 ****
  	return build_min_nt (COMPOUND_EXPR, op1, op2);
        op1 = build_non_dependent_expr (op1);
        op2 = build_non_dependent_expr (op2);
      }
  
!   result = build_new_op (COMPOUND_EXPR, LOOKUP_NORMAL, op1, op2, NULL_TREE);
    if (!result)
      result = build_compound_expr (op1, op2);
  
    if (processing_template_decl && result != error_mark_node)
      return build_min_non_dep (COMPOUND_EXPR, result, orig_op1, orig_op2);
--- 4374,4385 ----
  	return build_min_nt (COMPOUND_EXPR, op1, op2);
        op1 = build_non_dependent_expr (op1);
        op2 = build_non_dependent_expr (op2);
      }
  
!   result = build_new_op (COMPOUND_EXPR, LOOKUP_NORMAL, op1, op2, NULL_TREE,
! 			 /*overloaded_p=*/NULL);
    if (!result)
      result = build_compound_expr (op1, op2);
  
    if (processing_template_decl && result != error_mark_node)
      return build_min_non_dep (COMPOUND_EXPR, result, orig_op1, orig_op2);
*************** build_modify_expr (tree lhs, enum tree_c
*** 5066,5076 ****
  	  if (! IS_AGGR_TYPE (lhstype))
  	    /* Do the default thing.  */;
  	  else
  	    {
  	      result = build_new_op (MODIFY_EXPR, LOOKUP_NORMAL,
! 				     lhs, rhs, make_node (NOP_EXPR));
  	      if (result == NULL_TREE)
  		return error_mark_node;
  	      return result;
  	    }
  	  lhstype = olhstype;
--- 5071,5082 ----
  	  if (! IS_AGGR_TYPE (lhstype))
  	    /* Do the default thing.  */;
  	  else
  	    {
  	      result = build_new_op (MODIFY_EXPR, LOOKUP_NORMAL,
! 				     lhs, rhs, make_node (NOP_EXPR),
! 				     /*overloaded_p=*/NULL);
  	      if (result == NULL_TREE)
  		return error_mark_node;
  	      return result;
  	    }
  	  lhstype = olhstype;
*************** build_x_modify_expr (tree lhs, enum tree
*** 5278,5288 ****
  			 build_min_nt (modifycode, NULL_TREE, NULL_TREE), rhs);
  
    if (modifycode != NOP_EXPR)
      {
        tree rval = build_new_op (MODIFY_EXPR, LOOKUP_NORMAL, lhs, rhs,
! 				make_node (modifycode));
        if (rval)
  	return rval;
      }
    return build_modify_expr (lhs, modifycode, rhs);
  }
--- 5284,5295 ----
  			 build_min_nt (modifycode, NULL_TREE, NULL_TREE), rhs);
  
    if (modifycode != NOP_EXPR)
      {
        tree rval = build_new_op (MODIFY_EXPR, LOOKUP_NORMAL, lhs, rhs,
! 				make_node (modifycode),
! 				/*overloaded_p=*/NULL);
        if (rval)
  	return rval;
      }
    return build_modify_expr (lhs, modifycode, rhs);
  }
Index: cp/typeck2.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/typeck2.c,v
retrieving revision 1.153.4.1
diff -c -5 -p -r1.153.4.1 typeck2.c
*** cp/typeck2.c	25 Jan 2004 02:52:32 -0000	1.153.4.1
--- cp/typeck2.c	16 Mar 2004 21:30:53 -0000
*************** build_x_arrow (tree expr)
*** 1088,1098 ****
      }
  
    if (IS_AGGR_TYPE (type))
      {
        while ((expr = build_new_op (COMPONENT_REF, LOOKUP_NORMAL, expr,
! 				   NULL_TREE, NULL_TREE)))
  	{
  	  if (expr == error_mark_node)
  	    return error_mark_node;
  
  	  if (value_member (TREE_TYPE (expr), types_memoized))
--- 1088,1099 ----
      }
  
    if (IS_AGGR_TYPE (type))
      {
        while ((expr = build_new_op (COMPONENT_REF, LOOKUP_NORMAL, expr,
! 				   NULL_TREE, NULL_TREE,
! 				   /*overloaded_p=*/NULL)))
  	{
  	  if (expr == error_mark_node)
  	    return error_mark_node;
  
  	  if (value_member (TREE_TYPE (expr), types_memoized))
Index: testsuite/g++.dg/parse/non-dependent3.C
===================================================================
RCS file: testsuite/g++.dg/parse/non-dependent3.C
diff -N testsuite/g++.dg/parse/non-dependent3.C
*** /dev/null	1 Jan 1970 00:00:00 -0000
--- testsuite/g++.dg/parse/non-dependent3.C	16 Mar 2004 21:31:02 -0000
***************
*** 0 ****
--- 1,17 ----
+ // PR c++/14586
+ 
+ enum E { e }; 
+  
+ E & operator |= (E &f1, const E &f2); 
+  
+ E operator | (const E &f1, const E &f2) { 
+   E result = f1; 
+   result |= f2; 
+   return result; 
+ } 
+  
+ template <typename> void foo () { 
+   const E flags = e | e; 
+ } 
+  
+ template void foo<double> ();


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