From 8e51619a4c4f724a8ced224d4c4d5116d59a5b97 Mon Sep 17 00:00:00 2001
From: Jason Merrill <jason@redhat.com>
Date: Fri, 26 Jul 2002 16:10:43 -0400
Subject: [PATCH] function.c (assign_parms): Handle frontend-directed pass by
 invisible reference.

        * function.c (assign_parms): Handle frontend-directed pass by
        invisible reference.
cp/
        * call.c (build_over_call): Likewise.
        (cp_convert_parm_for_inlining): New fn.
        (convert_for_arg_passing): New fn.
        (convert_default_arg, build_over_call): Use it.
        (type_passed_as): New fn.
        * pt.c (tsubst_decl): Use it.
        * decl2.c (cp_build_parm_decl): New fn.
        (build_artificial_parm): Use it.
        (start_static_storage_duration_function): Likewise.
        * decl.c (start_cleanup_fn, grokdeclarater): Likewise.
        (grokparms): Don't mess with DECL_ARG_TYPE.
        * typeck.c (convert_arguments): Use convert_for_arg_passing.
        * cp-lang.c (LANG_HOOKS_TREE_INLINING_CONVERT_PARM_FOR_INLINING):
        Define.
        * cp-tree.h: Declare new fns.

From-SVN: r55781
---
 gcc/ChangeLog    |  5 +++++
 gcc/cp/ChangeLog | 18 +++++++++++++++
 gcc/cp/call.c    | 58 +++++++++++++++++++++++++++++++++++++++++-------
 gcc/cp/cp-lang.c |  3 +++
 gcc/cp/cp-tree.h |  4 ++++
 gcc/cp/decl.c    | 19 +++-------------
 gcc/cp/decl2.c   | 29 +++++++++++++++---------
 gcc/cp/init.c    |  4 +++-
 gcc/cp/pt.c      |  9 ++++----
 gcc/cp/typeck.c  |  6 +----
 gcc/function.c   |  9 ++++++++
 11 files changed, 118 insertions(+), 46 deletions(-)

diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 18e8f1cdd152..138d317e41f0 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,8 @@
+2002-07-26  Jason Merrill  <jason@redhat.com>
+
+	* function.c (assign_parms): Handle frontend-directed pass by
+	invisible reference.
+
 2002-07-26  Neil Booth  <neil@daikokuya.co.uk>
 
 	* doc/cppopts.texi: Update.
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 8fd963b3eadd..8fc09b11d22e 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,21 @@
+2002-07-26  Jason Merrill  <jason@redhat.com>
+
+	* call.c (build_over_call): Likewise.
+	(cp_convert_parm_for_inlining): New fn.
+        (convert_for_arg_passing): New fn.
+        (convert_default_arg, build_over_call): Use it.
+	(type_passed_as): New fn.
+	* pt.c (tsubst_decl): Use it.
+	* decl2.c (cp_build_parm_decl): New fn.
+	(build_artificial_parm): Use it.
+	(start_static_storage_duration_function): Likewise.
+	* decl.c (start_cleanup_fn, grokdeclarater): Likewise.
+	(grokparms): Don't mess with DECL_ARG_TYPE.
+	* typeck.c (convert_arguments): Use convert_for_arg_passing.
+	* cp-lang.c (LANG_HOOKS_TREE_INLINING_CONVERT_PARM_FOR_INLINING):
+	Define.
+	* cp-tree.h: Declare new fns.
+	
 2002-07-26  Neil Booth  <neil@daikokuya.co.uk>
 
 	* cp-tree.h (flag_operator_names): Remove.
diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index 141c7ac25379..1599d0b993f6 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -4128,15 +4128,60 @@ convert_default_arg (type, arg, fn, parmnum)
 
       arg = convert_for_initialization (0, type, arg, LOOKUP_NORMAL,
 					"default argument", fn, parmnum);
-      if (PROMOTE_PROTOTYPES
-	  && INTEGRAL_TYPE_P (type)
-	  && (TYPE_PRECISION (type) < TYPE_PRECISION (integer_type_node)))
-	arg = default_conversion (arg);
+      arg = convert_for_arg_passing (type, arg);
     }
 
   return arg;
 }
 
+/* Returns the type which will really be used for passing an argument of
+   type TYPE.  */
+
+tree
+type_passed_as (type)
+     tree type;
+{
+  /* Pass classes with copy ctors by invisible reference.  */
+  if (TREE_ADDRESSABLE (type))
+    type = build_reference_type (type);
+  else if (PROMOTE_PROTOTYPES
+	   && INTEGRAL_TYPE_P (type)
+	   && TYPE_PRECISION (type) < TYPE_PRECISION (integer_type_node))
+    type = integer_type_node;
+
+  return type;
+}
+
+/* Actually perform the appropriate conversion.  */
+
+tree
+convert_for_arg_passing (type, val)
+     tree type, val;
+{
+  /* Pass classes with copy ctors by invisible reference.  */
+  if (TREE_ADDRESSABLE (type))
+    val = build1 (ADDR_EXPR, build_reference_type (type), val);
+  else if (PROMOTE_PROTOTYPES
+	   && INTEGRAL_TYPE_P (type)
+	   && TYPE_PRECISION (type) < TYPE_PRECISION (integer_type_node))
+    val = default_conversion (val);
+  return val;
+}
+
+/* Convert VALUE for assignment into inlined parameter PARM.  */
+
+tree
+cp_convert_parm_for_inlining (parm, value, fn)
+     tree parm, value;
+     tree fn ATTRIBUTE_UNUSED;
+{
+  /* When inlining, we don't need to mess with invisible references, so
+     undo the ADDR_EXPR.  */
+  if (TREE_ADDRESSABLE (TREE_TYPE (parm)))
+    value = build_indirect_ref (value, NULL);
+  return value;
+}
+
 /* Subroutine of the various build_*_call functions.  Overload resolution
    has chosen a winning candidate CAND; build up a CALL_EXPR accordingly.
    ARGS is a TREE_LIST of the unconverted arguments to the call.  FLAGS is a
@@ -4222,10 +4267,7 @@ build_over_call (cand, args, flags)
       val = convert_like_with_context
 	(conv, TREE_VALUE (arg), fn, i - is_method);
 
-      if (PROMOTE_PROTOTYPES
-	  && INTEGRAL_TYPE_P (type)
-	  && (TYPE_PRECISION (type) < TYPE_PRECISION (integer_type_node)))
-	val = default_conversion (val);
+      val = convert_for_arg_passing (type, val);
       converted_args = tree_cons (NULL_TREE, val, converted_args);
     }
 
diff --git a/gcc/cp/cp-lang.c b/gcc/cp/cp-lang.c
index f482582c8c74..a44d4b6b8a19 100644
--- a/gcc/cp/cp-lang.c
+++ b/gcc/cp/cp-lang.c
@@ -120,6 +120,9 @@ static bool cxx_warn_unused_global_decl PARAMS ((tree));
 #undef LANG_HOOKS_TREE_INLINING_COPY_RES_DECL_FOR_INLINING
 #define LANG_HOOKS_TREE_INLINING_COPY_RES_DECL_FOR_INLINING \
   cp_copy_res_decl_for_inlining
+#undef LANG_HOOKS_TREE_INLINING_CONVERT_PARM_FOR_INLINING
+#define LANG_HOOKS_TREE_INLINING_CONVERT_PARM_FOR_INLINING \
+  cp_convert_parm_for_inlining
 #undef LANG_HOOKS_TREE_INLINING_ANON_AGGR_TYPE_P
 #define LANG_HOOKS_TREE_INLINING_ANON_AGGR_TYPE_P anon_aggr_type_p
 #undef LANG_HOOKS_TREE_INLINING_START_INLINING
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 6a2bda39dab4..ae88df2c8ce5 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -3679,6 +3679,9 @@ extern tree convert_default_arg                 PARAMS ((tree, tree, tree, int))
 extern tree convert_arg_to_ellipsis             PARAMS ((tree));
 extern tree build_x_va_arg                      PARAMS ((tree, tree));
 extern tree cxx_type_promotes_to		PARAMS ((tree));
+extern tree type_passed_as                      PARAMS ((tree));
+extern tree convert_for_arg_passing             PARAMS ((tree, tree));
+extern tree cp_convert_parm_for_inlining        PARAMS ((tree, tree, tree));
 extern int is_properly_derived_from             PARAMS ((tree, tree));
 extern tree initialize_reference                PARAMS ((tree, tree));
 extern tree strip_top_quals                     PARAMS ((tree));
@@ -3958,6 +3961,7 @@ extern void mark_used				PARAMS ((tree));
 extern tree handle_class_head			(enum tag_types, tree, tree, tree, int, int *);
 extern tree lookup_arg_dependent                PARAMS ((tree, tree, tree));
 extern void finish_static_data_member_decl      PARAMS ((tree, tree, tree, int));
+extern tree cp_build_parm_decl                  PARAMS ((tree, tree));
 extern tree build_artificial_parm               PARAMS ((tree, tree));
 extern tree get_guard                           PARAMS ((tree));
 extern tree get_guard_cond                      PARAMS ((tree));
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 337107baf62d..14021a411d15 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -8518,9 +8518,8 @@ start_cleanup_fn ()
     {
       tree parmdecl;
 
-      parmdecl = build_decl (PARM_DECL, NULL_TREE, ptr_type_node);
+      parmdecl = cp_build_parm_decl (NULL_TREE, ptr_type_node);
       DECL_CONTEXT (parmdecl) = fndecl;
-      DECL_ARG_TYPE (parmdecl) = ptr_type_node;
       TREE_USED (parmdecl) = 1;
       DECL_ARGUMENTS (fndecl) = parmdecl;
     }
@@ -11366,7 +11365,7 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
 
       for (args = TYPE_ARG_TYPES (type); args; args = TREE_CHAIN (args))
 	{
-	  tree decl = build_decl (PARM_DECL, NULL_TREE, TREE_VALUE (args));
+	  tree decl = cp_build_parm_decl (NULL_TREE, TREE_VALUE (args));
 
 	  TREE_CHAIN (decl) = decls;
 	  decls = decl;
@@ -11510,17 +11509,10 @@ friend declaration requires class-key, i.e. `friend %#T'",
 
     if (decl_context == PARM)
       {
-	decl = build_decl (PARM_DECL, declarator, type);
+	decl = cp_build_parm_decl (declarator, type);
 
 	bad_specifiers (decl, "parameter", virtualp, quals != NULL_TREE,
 			inlinep, friendp, raises != NULL_TREE);
-
-	/* Compute the type actually passed in the parmlist,
-	   for the case where there is no prototype.
-	   (For example, shorts and chars are passed as ints.)
-	   When there is a prototype, this is overridden later.  */
-
-	DECL_ARG_TYPE (decl) = type_promotes_to (type);
       }
     else if (decl_context == FIELD)
       {
@@ -12206,11 +12198,6 @@ grokparms (first_parm)
 			  decl, ptr ? "pointer" : "reference", t);
 	    }
 
-	  DECL_ARG_TYPE (decl) = TREE_TYPE (decl);
-	  if (PROMOTE_PROTOTYPES
-	      && INTEGRAL_TYPE_P (type)
-	      && TYPE_PRECISION (type) < TYPE_PRECISION (integer_type_node))
-	    DECL_ARG_TYPE (decl) = integer_type_node;
 	  if (!any_error && init)
 	    init = check_default_argument (decl, init);
 	  else
diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c
index 08fd777db39a..0a2da36c5b08 100644
--- a/gcc/cp/decl2.c
+++ b/gcc/cp/decl2.c
@@ -795,6 +795,19 @@ grok_x_components (specs)
   finish_member_declaration (build_decl (FIELD_DECL, NULL_TREE, t)); 
 }
 
+/* Build a PARM_DECL with NAME and TYPE, and set DECL_ARG_TYPE
+   appropriately.  */
+
+tree
+cp_build_parm_decl (name, type)
+     tree name;
+     tree type;
+{
+  tree parm = build_decl (PARM_DECL, name, type);
+  DECL_ARG_TYPE (parm) = type_passed_as (type);
+  return parm;
+}
+
 /* Returns a PARM_DECL for a parameter of the indicated TYPE, with the
    indicated NAME.  */
 
@@ -803,14 +816,11 @@ build_artificial_parm (name, type)
      tree name;
      tree type;
 {
-  tree parm;
-
-  parm = build_decl (PARM_DECL, name, type);
+  tree parm = cp_build_parm_decl (name, type);
   DECL_ARTIFICIAL (parm) = 1;
   /* All our artificial parms are implicitly `const'; they cannot be
      assigned to.  */
   TREE_READONLY (parm) = 1;
-  DECL_ARG_TYPE (parm) = type;
   return parm;
 }
 
@@ -2853,16 +2863,13 @@ start_static_storage_duration_function ()
   VARRAY_PUSH_TREE (ssdf_decls, ssdf_decl);
 
   /* Create the argument list.  */
-  initialize_p_decl = build_decl (PARM_DECL,
-				  get_identifier (INITIALIZE_P_IDENTIFIER),
-				  integer_type_node);
+  initialize_p_decl = cp_build_parm_decl
+    (get_identifier (INITIALIZE_P_IDENTIFIER), integer_type_node);
   DECL_CONTEXT (initialize_p_decl) = ssdf_decl;
-  DECL_ARG_TYPE (initialize_p_decl) = integer_type_node;
   TREE_USED (initialize_p_decl) = 1;
-  priority_decl = build_decl (PARM_DECL, get_identifier (PRIORITY_IDENTIFIER),
-			      integer_type_node);
+  priority_decl = cp_build_parm_decl
+    (get_identifier (PRIORITY_IDENTIFIER), integer_type_node);
   DECL_CONTEXT (priority_decl) = ssdf_decl;
-  DECL_ARG_TYPE (priority_decl) = integer_type_node;
   TREE_USED (priority_decl) = 1;
 
   TREE_CHAIN (initialize_p_decl) = priority_decl;
diff --git a/gcc/cp/init.c b/gcc/cp/init.c
index 31c1505afa6a..3b99c95ee3e7 100644
--- a/gcc/cp/init.c
+++ b/gcc/cp/init.c
@@ -2494,7 +2494,9 @@ build_new_1 (exp)
 	     constructor, that would fix the nesting problem and we could
 	     do away with this complexity.  But that would complicate other
 	     things; in particular, it would make it difficult to bail out
-	     if the allocation function returns null.  */
+	     if the allocation function returns null.  Er, no, it wouldn't;
+	     we just don't run the constructor.  The standard says it's
+	     unspecified whether or not the args are evaluated.  */
 
 	  if (cleanup)
 	    {
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 565b75fdfed2..ca8b2c2225a2 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -6012,7 +6012,7 @@ tsubst_decl (t, args, type, complain)
 	r = copy_node (t);
 	if (DECL_TEMPLATE_PARM_P (t))
 	  SET_DECL_TEMPLATE_PARM_P (r);
-	
+
 	TREE_TYPE (r) = type;
 	c_apply_type_quals_to_decl (cp_type_quals (type), r);
 
@@ -6023,10 +6023,9 @@ tsubst_decl (t, args, type, complain)
 				     complain, in_decl);
 
 	DECL_CONTEXT (r) = NULL_TREE;
-	if (!DECL_TEMPLATE_PARM_P (r) && PROMOTE_PROTOTYPES
-	    && INTEGRAL_TYPE_P (type)
-	    && TYPE_PRECISION (type) < TYPE_PRECISION (integer_type_node))
-	  DECL_ARG_TYPE (r) = integer_type_node;
+
+	if (!DECL_TEMPLATE_PARM_P (r))
+	  DECL_ARG_TYPE (r) = type_passed_as (type);
 	if (TREE_CHAIN (t))
 	  TREE_CHAIN (r) = tsubst (TREE_CHAIN (t), args,
 				   complain, TREE_CHAIN (t));
diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
index e333d3e58770..07199d60b41c 100644
--- a/gcc/cp/typeck.c
+++ b/gcc/cp/typeck.c
@@ -3112,11 +3112,7 @@ convert_arguments (typelist, values, fndecl, flags)
 	      parmval = convert_for_initialization
 		(NULL_TREE, type, val, flags,
 		 "argument passing", fndecl, i);
-	      if (PROMOTE_PROTOTYPES
-		  && INTEGRAL_TYPE_P (type)
-		  && (TYPE_PRECISION (type)
-		      < TYPE_PRECISION (integer_type_node)))
-		parmval = default_conversion (parmval);
+	      parmval = convert_for_arg_passing (type, parmval);
 	    }
 
 	  if (parmval == error_mark_node)
diff --git a/gcc/function.c b/gcc/function.c
index 2a59d59459b2..98c196587084 100644
--- a/gcc/function.c
+++ b/gcc/function.c
@@ -4425,6 +4425,15 @@ assign_parms (fndecl)
 	  passed_pointer = 1;
 	  passed_mode = nominal_mode = Pmode;
 	}
+      /* See if the frontend wants to pass this by invisible reference.  */
+      else if (passed_type != nominal_type
+	       && POINTER_TYPE_P (passed_type)
+	       && TREE_TYPE (passed_type) == nominal_type)
+	{
+	  nominal_type = passed_type;
+	  passed_pointer = 1;
+	  passed_mode = nominal_mode = Pmode;
+	}
 
       promoted_mode = passed_mode;