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]

RFC: C++ PATCH to implement late-specified return types


It was pretty straightforward to extend the other auto work to handle late-specified return types as well, so I went ahead and did it.

Unfortunately, this functionality is pretty useless at the moment due to a bug of very long standing that wasn't very important previously: the standard says (in 3.3.2):

3.3.1: The point of declaration for a name is immediately after its complete declarator (clause 8) and before its initializer (if any)

3.3.2: The potential scope of a function parameter name ... begins at its point of declaration.

But in G++ we don't declare function parameters until we've seen the entire enclosing function declarator. So as a result, code like

template<class T, class U>
auto add(T t, U u) -> decltype(t+u);

gets rejected because "t" and "u" haven't been declared yet when we're parsing the return type.

This bug can be seen without involving any C++0xisms,

  template <class T>
  void f (T t, char (*buf_p)[sizeof(t)]) {}

but it's much more of an issue for late-specified return types, as the whole point of the extension is to allow the use of the parameter names for a more compact description of the type you want.

So my question is, should I apply this now and then fix that bug, or hold off on this patch until that bug is fixed as well?

I remember being aware of this bug years ago, but can't seem to find a Bugzilla entry; perhaps I noticed it when running a commercial testsuite.

Interestingly, the EDG front end seems to have the same bug.

2008-08-31  Jason Merrill  <jason@redhat.com>

	Implement late-specified return type using 'auto'.
	* cp-tree.h (struct cp_declarator): Add late_return_type field to
	function declarator.
	* parser.c (cp_parser_late_return_type_opt): New fn.
	(cp_parser_direct_declarator): Use it.
	(make_call_declarator): Put it in the declarator.
	* decl.c (grokdeclarator): Splice in late-specified return type.
	* pt.c (splice_late_return_type): New fn.

Index: cp/decl.c
===================================================================
*** cp/decl.c	(revision 139810)
--- cp/decl.c	(working copy)
*************** grokdeclarator (const cp_declarator *dec
*** 8178,8183 ****
--- 8178,8189 ----
  	    /* Pick up the exception specifications.  */
  	    raises = declarator->u.function.exception_specification;
  
+ 	    /* Handle a late-specified return type.  */
+ 	    type = splice_late_return_type
+ 	      (type, declarator->u.function.late_return_type);
+ 	    if (type == error_mark_node)
+ 	      return error_mark_node;
+ 
  	    /* Say it's a definition only for the CALL_EXPR
  	       closest to the identifier.  */
  	    funcdecl_p = inner_declarator && inner_declarator->kind == cdk_id;
Index: cp/cp-tree.h
===================================================================
*** cp/cp-tree.h	(revision 139810)
--- cp/cp-tree.h	(working copy)
*************** struct cp_declarator {
*** 4108,4113 ****
--- 4108,4115 ----
        cp_cv_quals qualifiers;
        /* The exception-specification for the function.  */
        tree exception_specification;
+       /* The late-specified return type, if any.  */
+       tree late_return_type;
      } function;
      /* For arrays.  */
      struct {
*************** extern tree check_explicit_specializatio
*** 4524,4529 ****
--- 4526,4532 ----
  extern tree make_auto				(void);
  extern tree do_auto_deduction			(tree, tree, tree);
  extern tree type_uses_auto			(tree);
+ extern tree splice_late_return_type		(tree, tree);
  extern bool is_auto				(const_tree);
  extern tree process_template_parm		(tree, tree, bool, bool);
  extern tree end_template_parm_list		(tree);
Index: cp/pt.c
===================================================================
*** cp/pt.c	(revision 139811)
--- cp/pt.c	(working copy)
*************** do_auto_deduction (tree type, tree init,
*** 16769,16774 ****
--- 16769,16791 ----
    return tsubst (type, targs, tf_warning_or_error, NULL_TREE);
  }
  
+ /* Substitutes LATE_RETURN_TYPE for 'auto' in TYPE and returns the
+    result.  */
+ 
+ tree
+ splice_late_return_type (tree type, tree late_return_type)
+ {
+   tree argvec;
+ 
+   if (late_return_type == NULL_TREE)
+     return type;
+   argvec = make_tree_vec (1);
+   TREE_VEC_ELT (argvec, 0) = late_return_type;
+   if (processing_template_decl)
+     argvec = add_to_template_args (current_template_args (), argvec);
+   return tsubst (type, argvec, tf_warning_or_error, NULL_TREE);
+ }
+ 
  /* Returns true iff TYPE is a TEMPLATE_TYPE_PARM representing 'auto'.  */
  
  bool
Index: cp/parser.c
===================================================================
*** cp/parser.c	(revision 139810)
--- cp/parser.c	(working copy)
*************** clear_decl_specs (cp_decl_specifier_seq 
*** 853,859 ****
     VAR_DECLs or FUNCTION_DECLs) should do that directly.  */
  
  static cp_declarator *make_call_declarator
!   (cp_declarator *, cp_parameter_declarator *, cp_cv_quals, tree);
  static cp_declarator *make_array_declarator
    (cp_declarator *, tree);
  static cp_declarator *make_pointer_declarator
--- 853,859 ----
     VAR_DECLs or FUNCTION_DECLs) should do that directly.  */
  
  static cp_declarator *make_call_declarator
!   (cp_declarator *, cp_parameter_declarator *, cp_cv_quals, tree, tree);
  static cp_declarator *make_array_declarator
    (cp_declarator *, tree);
  static cp_declarator *make_pointer_declarator
*************** cp_declarator *
*** 1015,1021 ****
  make_call_declarator (cp_declarator *target,
  		      cp_parameter_declarator *parms,
  		      cp_cv_quals cv_qualifiers,
! 		      tree exception_specification)
  {
    cp_declarator *declarator;
  
--- 1015,1022 ----
  make_call_declarator (cp_declarator *target,
  		      cp_parameter_declarator *parms,
  		      cp_cv_quals cv_qualifiers,
! 		      tree exception_specification,
! 		      tree late_return_type)
  {
    cp_declarator *declarator;
  
*************** make_call_declarator (cp_declarator *tar
*** 1024,1029 ****
--- 1025,1031 ----
    declarator->u.function.parameters = parms;
    declarator->u.function.qualifiers = cv_qualifiers;
    declarator->u.function.exception_specification = exception_specification;
+   declarator->u.function.late_return_type = late_return_type;
    if (target)
      {
        declarator->parameter_pack_p = target->parameter_pack_p;
*************** static enum tree_code cp_parser_ptr_oper
*** 1726,1731 ****
--- 1728,1735 ----
    (cp_parser *, tree *, cp_cv_quals *);
  static cp_cv_quals cp_parser_cv_qualifier_seq_opt
    (cp_parser *);
+ static tree cp_parser_late_return_type_opt
+   (cp_parser *);
  static tree cp_parser_declarator_id
    (cp_parser *, bool);
  static tree cp_parser_type_id
*************** cp_parser_direct_declarator (cp_parser* 
*** 13021,13026 ****
--- 13025,13031 ----
  		{
  		  cp_cv_quals cv_quals;
  		  tree exception_specification;
+ 		  tree late_return;
  
  		  if (ctor_dtor_or_conv_p)
  		    *ctor_dtor_or_conv_p = *ctor_dtor_or_conv_p < 0;
*************** cp_parser_direct_declarator (cp_parser* 
*** 13034,13044 ****
  		  exception_specification
  		    = cp_parser_exception_specification_opt (parser);
  
  		  /* Create the function-declarator.  */
  		  declarator = make_call_declarator (declarator,
  						     params,
  						     cv_quals,
! 						     exception_specification);
  		  /* Any subsequent parameter lists are to do with
  		     return type, so are not those of the declared
  		     function.  */
--- 13039,13053 ----
  		  exception_specification
  		    = cp_parser_exception_specification_opt (parser);
  
+ 		  late_return
+ 		    = cp_parser_late_return_type_opt (parser);
+ 
  		  /* Create the function-declarator.  */
  		  declarator = make_call_declarator (declarator,
  						     params,
  						     cv_quals,
! 						     exception_specification,
! 						     late_return);
  		  /* Any subsequent parameter lists are to do with
  		     return type, so are not those of the declared
  		     function.  */
*************** cp_parser_cv_qualifier_seq_opt (cp_parse
*** 13516,13521 ****
--- 13525,13554 ----
    return cv_quals;
  }
  
+ /* Parse a late-specified return type, if any.  This is not a separate
+    non-terminal, but part of a function declarator, which looks like
+ 
+    -> type-id
+ 
+    Returns the type indicated by the type-id.  */
+ 
+ static tree
+ cp_parser_late_return_type_opt (cp_parser* parser)
+ {
+   cp_token *token;
+ 
+   /* Peek at the next token.  */
+   token = cp_lexer_peek_token (parser->lexer);
+   /* A late-specified return type is indicated by an initial '->'. */
+   if (token->type != CPP_DEREF)
+     return NULL_TREE;
+ 
+   /* Consume the ->.  */
+   cp_lexer_consume_token (parser->lexer);
+ 
+   return cp_parser_type_id (parser);
+ }
+ 
  /* Parse a declarator-id.
  
     declarator-id:
Index: testsuite/g++.dg/cpp0x/auto6.C
===================================================================
*** testsuite/g++.dg/cpp0x/auto6.C	(revision 0)
--- testsuite/g++.dg/cpp0x/auto6.C	(revision 0)
***************
*** 0 ****
--- 1,9 ----
+ // { dg-options "-std=c++0x" }
+ 
+ auto f() -> int
+ {
+   return 0;
+ }
+ 
+ template<class T, class U>
+ auto add(T t, U u) -> decltype (t+u); // { dg-bogus "not declared" "" { xfail *-*-* } }

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