aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Jacobowitz <drow@false.org>2007-09-23 16:25:06 +0000
committerDaniel Jacobowitz <drow@false.org>2007-09-23 16:25:06 +0000
commit41f1b6975dce5616800a8ff1acb544019c7bc132 (patch)
treef3e49925507634d70cb6d6e1fbd9ce7c6b8ec313
parent3f213f78ed9182dbdeb3500dab729a6aad17dfd9 (diff)
downloadfsf-binutils-gdb-41f1b6975dce5616800a8ff1acb544019c7bc132.zip
fsf-binutils-gdb-41f1b6975dce5616800a8ff1acb544019c7bc132.tar.gz
fsf-binutils-gdb-41f1b6975dce5616800a8ff1acb544019c7bc132.tar.bz2
* infcall.c (call_function_by_hand): Handle language-specific
pass and return by reference. * cp-abi.c (cp_pass_by_reference): New. * cp-abi.h (cp_pass_by_reference): Declare. (struct cp_abi_ops): Add pass_by_reference. * gnu-v3-abi.c (gnuv3_pass_by_reference): New. (init_gnuv3_ops): Set pass_by_reference. * language.c (language_pass_by_reference): New. (default_pass_by_reference): New. (unknown_language_defn, auto_language_defn, local_language_defn): Add default_pass_by_reference. * langauge.h (struct language_defn): Add la_pass_by_reference. (language_pass_by_reference, default_pass_by_reference): Declare. * ada-lang.c (ada_language_defn): Add default_pass_by_reference. * c-lang.c (c_language_defn, asm_language_defn) (minimal_language_defn): Likewise. (cplus_language_defn): Add cp_pass_by_reference. * f-lang.c (f_language_defn): Add default_pass_by_reference. * jv-lang.c (java_language_defn): Likewise. * m2-lang.c (m2_language_defn): Likewise. * objc-lang.c (objc_language_defn): Likewise. * p-lang.c (pascal_language_defn): Likewise. * scm-lang.c (scm_language_defn): Likewise * gdb.cp/pass-by-ref.cc, gdb.cp/pass-by-ref.exp: New files.
-rw-r--r--gdb/ChangeLog28
-rw-r--r--gdb/ada-lang.c1
-rw-r--r--gdb/c-lang.c4
-rw-r--r--gdb/cp-abi.c8
-rw-r--r--gdb/cp-abi.h5
-rw-r--r--gdb/f-lang.c1
-rw-r--r--gdb/gnu-v3-abi.c82
-rw-r--r--gdb/infcall.c66
-rw-r--r--gdb/jv-lang.c1
-rw-r--r--gdb/language.c20
-rw-r--r--gdb/language.h13
-rw-r--r--gdb/m2-lang.c1
-rw-r--r--gdb/objc-lang.c1
-rw-r--r--gdb/p-lang.c1
-rw-r--r--gdb/scm-lang.c1
-rw-r--r--gdb/testsuite/ChangeLog4
-rw-r--r--gdb/testsuite/gdb.cp/pass-by-ref.cc79
-rw-r--r--gdb/testsuite/gdb.cp/pass-by-ref.exp41
18 files changed, 346 insertions, 11 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index b9ba285..3c55358 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,3 +1,31 @@
+2007-09-23 Daniel Jacobowitz <dan@codesourcery.com>
+
+ * infcall.c (call_function_by_hand): Handle language-specific
+ pass and return by reference.
+
+ * cp-abi.c (cp_pass_by_reference): New.
+ * cp-abi.h (cp_pass_by_reference): Declare.
+ (struct cp_abi_ops): Add pass_by_reference.
+ * gnu-v3-abi.c (gnuv3_pass_by_reference): New.
+ (init_gnuv3_ops): Set pass_by_reference.
+
+ * language.c (language_pass_by_reference): New.
+ (default_pass_by_reference): New.
+ (unknown_language_defn, auto_language_defn, local_language_defn): Add
+ default_pass_by_reference.
+ * langauge.h (struct language_defn): Add la_pass_by_reference.
+ (language_pass_by_reference, default_pass_by_reference): Declare.
+ * ada-lang.c (ada_language_defn): Add default_pass_by_reference.
+ * c-lang.c (c_language_defn, asm_language_defn)
+ (minimal_language_defn): Likewise.
+ (cplus_language_defn): Add cp_pass_by_reference.
+ * f-lang.c (f_language_defn): Add default_pass_by_reference.
+ * jv-lang.c (java_language_defn): Likewise.
+ * m2-lang.c (m2_language_defn): Likewise.
+ * objc-lang.c (objc_language_defn): Likewise.
+ * p-lang.c (pascal_language_defn): Likewise.
+ * scm-lang.c (scm_language_defn): Likewise
+
2007-09-23 Vladimir Prus <vladimir@codesourcery.com>
Allow a code breakpoint to have several locations
diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c
index 4960fda..04135fe 100644
--- a/gdb/ada-lang.c
+++ b/gdb/ada-lang.c
@@ -10441,6 +10441,7 @@ const struct language_defn ada_language_defn = {
ada_get_gdb_completer_word_break_characters,
ada_language_arch_info,
ada_print_array_index,
+ default_pass_by_reference,
LANG_MAGIC
};
diff --git a/gdb/c-lang.c b/gdb/c-lang.c
index 7b9ebbb..7855551 100644
--- a/gdb/c-lang.c
+++ b/gdb/c-lang.c
@@ -606,6 +606,7 @@ const struct language_defn c_language_defn =
default_word_break_characters,
c_language_arch_info,
default_print_array_index,
+ default_pass_by_reference,
LANG_MAGIC
};
@@ -711,6 +712,7 @@ const struct language_defn cplus_language_defn =
default_word_break_characters,
cplus_language_arch_info,
default_print_array_index,
+ cp_pass_by_reference,
LANG_MAGIC
};
@@ -747,6 +749,7 @@ const struct language_defn asm_language_defn =
default_word_break_characters,
c_language_arch_info, /* FIXME: la_language_arch_info. */
default_print_array_index,
+ default_pass_by_reference,
LANG_MAGIC
};
@@ -788,6 +791,7 @@ const struct language_defn minimal_language_defn =
default_word_break_characters,
c_language_arch_info,
default_print_array_index,
+ default_pass_by_reference,
LANG_MAGIC
};
diff --git a/gdb/cp-abi.c b/gdb/cp-abi.c
index 9d5d60c..ced1a96 100644
--- a/gdb/cp-abi.c
+++ b/gdb/cp-abi.c
@@ -135,6 +135,14 @@ cplus_method_ptr_to_value (struct value **this_p, struct value *method_ptr)
return (*current_cp_abi.method_ptr_to_value) (this_p, method_ptr);
}
+int
+cp_pass_by_reference (struct type *type)
+{
+ if ((current_cp_abi.pass_by_reference) == NULL)
+ return 0;
+ return (*current_cp_abi.pass_by_reference) (type);
+}
+
/* Set the current C++ ABI to SHORT_NAME. */
static int
diff --git a/gdb/cp-abi.h b/gdb/cp-abi.h
index a0efb33..2b1838d 100644
--- a/gdb/cp-abi.h
+++ b/gdb/cp-abi.h
@@ -172,6 +172,10 @@ void cplus_make_method_ptr (gdb_byte *CONTENTS, CORE_ADDR address,
CORE_ADDR cplus_skip_trampoline (struct frame_info *frame, CORE_ADDR stop_pc);
+/* Return non-zero if an argument of type TYPE should be passed by reference
+ instead of value. */
+extern int cp_pass_by_reference (struct type *type);
+
struct cp_abi_ops
{
const char *shortname;
@@ -195,6 +199,7 @@ struct cp_abi_ops
void (*make_method_ptr) (gdb_byte *, CORE_ADDR, int);
struct value * (*method_ptr_to_value) (struct value **, struct value *);
CORE_ADDR (*skip_trampoline) (struct frame_info *, CORE_ADDR);
+ int (*pass_by_reference) (struct type *type);
};
diff --git a/gdb/f-lang.c b/gdb/f-lang.c
index b0189a2..0006ff8 100644
--- a/gdb/f-lang.c
+++ b/gdb/f-lang.c
@@ -503,6 +503,7 @@ const struct language_defn f_language_defn =
default_word_break_characters,
f_language_arch_info,
default_print_array_index,
+ default_pass_by_reference,
LANG_MAGIC
};
diff --git a/gdb/gnu-v3-abi.c b/gdb/gnu-v3-abi.c
index 469fc57..c3e07a1 100644
--- a/gdb/gnu-v3-abi.c
+++ b/gdb/gnu-v3-abi.c
@@ -716,6 +716,87 @@ gnuv3_skip_trampoline (struct frame_info *frame, CORE_ADDR stop_pc)
return real_stop_pc;
}
+/* Return nonzero if a type should be passed by reference.
+
+ The rule in the v3 ABI document comes from section 3.1.1. If the
+ type has a non-trivial copy constructor or destructor, then the
+ caller must make a copy (by calling the copy constructor if there
+ is one or perform the copy itself otherwise), pass the address of
+ the copy, and then destroy the temporary (if necessary).
+
+ For return values with non-trivial copy constructors or
+ destructors, space will be allocated in the caller, and a pointer
+ will be passed as the first argument (preceding "this").
+
+ We don't have a bulletproof mechanism for determining whether a
+ constructor or destructor is trivial. For GCC and DWARF2 debug
+ information, we can check the artificial flag.
+
+ We don't do anything with the constructors or destructors,
+ but we have to get the argument passing right anyway. */
+static int
+gnuv3_pass_by_reference (struct type *type)
+{
+ int fieldnum, fieldelem;
+
+ CHECK_TYPEDEF (type);
+
+ /* We're only interested in things that can have methods. */
+ if (TYPE_CODE (type) != TYPE_CODE_STRUCT
+ && TYPE_CODE (type) != TYPE_CODE_CLASS
+ && TYPE_CODE (type) != TYPE_CODE_UNION)
+ return 0;
+
+ for (fieldnum = 0; fieldnum < TYPE_NFN_FIELDS (type); fieldnum++)
+ for (fieldelem = 0; fieldelem < TYPE_FN_FIELDLIST_LENGTH (type, fieldnum);
+ fieldelem++)
+ {
+ struct fn_field *fn = TYPE_FN_FIELDLIST1 (type, fieldnum);
+ char *name = TYPE_FN_FIELDLIST_NAME (type, fieldnum);
+ struct type *fieldtype = TYPE_FN_FIELD_TYPE (fn, fieldelem);
+
+ /* If this function is marked as artificial, it is compiler-generated,
+ and we assume it is trivial. */
+ if (TYPE_FN_FIELD_ARTIFICIAL (fn, fieldelem))
+ continue;
+
+ /* If we've found a destructor, we must pass this by reference. */
+ if (name[0] == '~')
+ return 1;
+
+ /* If the mangled name of this method doesn't indicate that it
+ is a constructor, we're not interested.
+
+ FIXME drow/2007-09-23: We could do this using the name of
+ the method and the name of the class instead of dealing
+ with the mangled name. We don't have a convenient function
+ to strip off both leading scope qualifiers and trailing
+ template arguments yet. */
+ if (!is_constructor_name (TYPE_FN_FIELD_PHYSNAME (fn, fieldelem)))
+ continue;
+
+ /* If this method takes two arguments, and the second argument is
+ a reference to this class, then it is a copy constructor. */
+ if (TYPE_NFIELDS (fieldtype) == 2
+ && TYPE_CODE (TYPE_FIELD_TYPE (fieldtype, 1)) == TYPE_CODE_REF
+ && check_typedef (TYPE_TARGET_TYPE (TYPE_FIELD_TYPE (fieldtype, 1))) == type)
+ return 1;
+ }
+
+ /* Even if all the constructors and destructors were artificial, one
+ of them may have invoked a non-artificial constructor or
+ destructor in a base class. If any base class needs to be passed
+ by reference, so does this class. Similarly for members, which
+ are constructed whenever this class is. We do not need to worry
+ about recursive loops here, since we are only looking at members
+ of complete class type. */
+ for (fieldnum = 0; fieldnum < TYPE_NFIELDS (type); fieldnum++)
+ if (gnuv3_pass_by_reference (TYPE_FIELD_TYPE (type, fieldnum)))
+ return 1;
+
+ return 0;
+}
+
static void
init_gnuv3_ops (void)
{
@@ -738,6 +819,7 @@ init_gnuv3_ops (void)
gnu_v3_abi_ops.make_method_ptr = gnuv3_make_method_ptr;
gnu_v3_abi_ops.method_ptr_to_value = gnuv3_method_ptr_to_value;
gnu_v3_abi_ops.skip_trampoline = gnuv3_skip_trampoline;
+ gnu_v3_abi_ops.pass_by_reference = gnuv3_pass_by_reference;
}
extern initialize_file_ftype _initialize_gnu_v3_abi; /* -Wmissing-prototypes */
diff --git a/gdb/infcall.c b/gdb/infcall.c
index b603da8..3012d7f 100644
--- a/gdb/infcall.c
+++ b/gdb/infcall.c
@@ -339,8 +339,8 @@ call_function_by_hand (struct value *function, int nargs, struct value **args)
{
CORE_ADDR sp;
CORE_ADDR dummy_addr;
- struct type *values_type;
- unsigned char struct_return;
+ struct type *values_type, *target_values_type;
+ unsigned char struct_return = 0, lang_struct_return = 0;
CORE_ADDR struct_addr = 0;
struct regcache *retbuf;
struct cleanup *retbuf_cleanup;
@@ -354,6 +354,7 @@ call_function_by_hand (struct value *function, int nargs, struct value **args)
struct regcache *caller_regcache;
struct cleanup *caller_regcache_cleanup;
struct frame_id dummy_id;
+ struct cleanup *args_cleanup;
if (TYPE_CODE (ftype) == TYPE_CODE_PTR)
ftype = check_typedef (TYPE_TARGET_TYPE (ftype));
@@ -460,10 +461,30 @@ call_function_by_hand (struct value *function, int nargs, struct value **args)
using_gcc = (b == NULL ? 2 : BLOCK_GCC_COMPILED (b));
}
- /* Are we returning a value using a structure return or a normal
- value return? */
+ /* Are we returning a value using a structure return (passing a
+ hidden argument pointing to storage) or a normal value return?
+ There are two cases: language-mandated structure return and
+ target ABI structure return. The variable STRUCT_RETURN only
+ describes the latter. The language version is handled by passing
+ the return location as the first parameter to the function,
+ even preceding "this". This is different from the target
+ ABI version, which is target-specific; for instance, on ia64
+ the first argument is passed in out0 but the hidden structure
+ return pointer would normally be passed in r8. */
+
+ if (language_pass_by_reference (values_type))
+ {
+ lang_struct_return = 1;
- struct_return = using_struct_return (values_type, using_gcc);
+ /* Tell the target specific argument pushing routine not to
+ expect a value. */
+ target_values_type = builtin_type_void;
+ }
+ else
+ {
+ struct_return = using_struct_return (values_type, using_gcc);
+ target_values_type = values_type;
+ }
/* Determine the location of the breakpoint (and possibly other
stuff) that the called function will return to. The SPARC, for a
@@ -482,7 +503,7 @@ call_function_by_hand (struct value *function, int nargs, struct value **args)
if (gdbarch_inner_than (current_gdbarch, 1, 2))
{
sp = push_dummy_code (current_gdbarch, sp, funaddr,
- using_gcc, args, nargs, values_type,
+ using_gcc, args, nargs, target_values_type,
&real_pc, &bp_addr, get_current_regcache ());
dummy_addr = sp;
}
@@ -490,7 +511,7 @@ call_function_by_hand (struct value *function, int nargs, struct value **args)
{
dummy_addr = sp;
sp = push_dummy_code (current_gdbarch, sp, funaddr,
- using_gcc, args, nargs, values_type,
+ using_gcc, args, nargs, target_values_type,
&real_pc, &bp_addr, get_current_regcache ());
}
break;
@@ -557,9 +578,12 @@ call_function_by_hand (struct value *function, int nargs, struct value **args)
param_type = TYPE_FIELD_TYPE (ftype, i);
else
param_type = NULL;
-
+
args[i] = value_arg_coerce (args[i], param_type, prototyped);
+ if (param_type != NULL && language_pass_by_reference (param_type))
+ args[i] = value_addr (args[i]);
+
/* elz: this code is to handle the case in which the function
to be called has a pointer to function as parameter and the
corresponding actual argument is the address of a function
@@ -659,7 +683,7 @@ You must use a pointer to function type variable. Command ignored."), arg_name);
stack, if necessary. Make certain that the value is correctly
aligned. */
- if (struct_return)
+ if (struct_return || lang_struct_return)
{
int len = TYPE_LENGTH (values_type);
if (gdbarch_inner_than (current_gdbarch, 1, 2))
@@ -684,6 +708,22 @@ You must use a pointer to function type variable. Command ignored."), arg_name);
}
}
+ if (lang_struct_return)
+ {
+ struct value **new_args;
+
+ /* Add the new argument to the front of the argument list. */
+ new_args = xmalloc (sizeof (struct value *) * (nargs + 1));
+ new_args[0] = value_from_pointer (lookup_pointer_type (values_type),
+ struct_addr);
+ memcpy (&new_args[1], &args[0], sizeof (struct value *) * nargs);
+ args = new_args;
+ nargs++;
+ args_cleanup = make_cleanup (xfree, args);
+ }
+ else
+ args_cleanup = make_cleanup (null_cleanup, NULL);
+
/* Create the dummy stack frame. Pass in the call dummy address as,
presumably, the ABI code knows where, in the call dummy, the
return address should be pointed. */
@@ -691,6 +731,8 @@ You must use a pointer to function type variable. Command ignored."), arg_name);
get_current_regcache (), bp_addr, nargs, args,
sp, struct_return, struct_addr);
+ do_cleanups (args_cleanup);
+
/* Set up a frame ID for the dummy frame so we can pass it to
set_momentary_breakpoint. We need to give the breakpoint a frame
ID so that the breakpoint code can correctly re-identify the
@@ -882,7 +924,9 @@ the function call)."), name);
{
struct value *retval = NULL;
- if (TYPE_CODE (values_type) == TYPE_CODE_VOID)
+ if (lang_struct_return)
+ retval = value_at (values_type, struct_addr);
+ else if (TYPE_CODE (target_values_type) == TYPE_CODE_VOID)
{
/* If the function returns void, don't bother fetching the
return value. */
@@ -892,7 +936,7 @@ the function call)."), name);
{
struct gdbarch *arch = current_gdbarch;
- switch (gdbarch_return_value (arch, values_type, NULL, NULL, NULL))
+ switch (gdbarch_return_value (arch, target_values_type, NULL, NULL, NULL))
{
case RETURN_VALUE_REGISTER_CONVENTION:
case RETURN_VALUE_ABI_RETURNS_ADDRESS:
diff --git a/gdb/jv-lang.c b/gdb/jv-lang.c
index 3460184..d28df02 100644
--- a/gdb/jv-lang.c
+++ b/gdb/jv-lang.c
@@ -1115,6 +1115,7 @@ const struct language_defn java_language_defn =
default_word_break_characters,
c_language_arch_info,
default_print_array_index,
+ default_pass_by_reference,
LANG_MAGIC
};
diff --git a/gdb/language.c b/gdb/language.c
index 3cc513f..d5c6a94 100644
--- a/gdb/language.c
+++ b/gdb/language.c
@@ -1045,6 +1045,23 @@ language_class_name_from_physname (const struct language_defn *current_language,
return NULL;
}
+/* Return non-zero if TYPE should be passed (and returned) by
+ reference at the language level. */
+int
+language_pass_by_reference (struct type *type)
+{
+ return current_language->la_pass_by_reference (type);
+}
+
+/* Return zero; by default, types are passed by value at the language
+ level. The target ABI may pass or return some structs by reference
+ independent of this. */
+int
+default_pass_by_reference (struct type *type)
+{
+ return 0;
+}
+
/* Return the default string containing the list of characters
delimiting words. This is a reasonable default value that
most languages should be able to use. */
@@ -1191,6 +1208,7 @@ const struct language_defn unknown_language_defn =
default_word_break_characters,
unknown_language_arch_info, /* la_language_arch_info. */
default_print_array_index,
+ default_pass_by_reference,
LANG_MAGIC
};
@@ -1228,6 +1246,7 @@ const struct language_defn auto_language_defn =
default_word_break_characters,
unknown_language_arch_info, /* la_language_arch_info. */
default_print_array_index,
+ default_pass_by_reference,
LANG_MAGIC
};
@@ -1264,6 +1283,7 @@ const struct language_defn local_language_defn =
default_word_break_characters,
unknown_language_arch_info, /* la_language_arch_info. */
default_print_array_index,
+ default_pass_by_reference,
LANG_MAGIC
};
diff --git a/gdb/language.h b/gdb/language.h
index e6dc544..3649b00 100644
--- a/gdb/language.h
+++ b/gdb/language.h
@@ -280,6 +280,10 @@ struct language_defn
int format,
enum val_prettyprint pretty);
+ /* Return non-zero if TYPE should be passed (and returned) by
+ reference at the language level. */
+ int (*la_pass_by_reference) (struct type *type);
+
/* Add fields above this point, so the magic number is always last. */
/* Magic number for compat checking */
@@ -471,4 +475,13 @@ extern void default_print_array_index (struct value *index_value,
int format,
enum val_prettyprint pretty);
+/* Return non-zero if TYPE should be passed (and returned) by
+ reference at the language level. */
+int language_pass_by_reference (struct type *type);
+
+/* Return zero; by default, types are passed by value at the language
+ level. The target ABI may pass or return some structs by reference
+ independent of this. */
+int default_pass_by_reference (struct type *type);
+
#endif /* defined (LANGUAGE_H) */
diff --git a/gdb/m2-lang.c b/gdb/m2-lang.c
index a2014bb..128869c 100644
--- a/gdb/m2-lang.c
+++ b/gdb/m2-lang.c
@@ -459,6 +459,7 @@ const struct language_defn m2_language_defn =
default_word_break_characters,
m2_language_arch_info,
default_print_array_index,
+ default_pass_by_reference,
LANG_MAGIC
};
diff --git a/gdb/objc-lang.c b/gdb/objc-lang.c
index ffe3d03..d1771d9 100644
--- a/gdb/objc-lang.c
+++ b/gdb/objc-lang.c
@@ -668,6 +668,7 @@ const struct language_defn objc_language_defn = {
default_word_break_characters,
c_language_arch_info,
default_print_array_index,
+ default_pass_by_reference,
LANG_MAGIC
};
diff --git a/gdb/p-lang.c b/gdb/p-lang.c
index e1a656d..ab204a1 100644
--- a/gdb/p-lang.c
+++ b/gdb/p-lang.c
@@ -525,6 +525,7 @@ const struct language_defn pascal_language_defn =
default_word_break_characters,
pascal_language_arch_info,
default_print_array_index,
+ default_pass_by_reference,
LANG_MAGIC
};
diff --git a/gdb/scm-lang.c b/gdb/scm-lang.c
index a6e5622..a8de4b0 100644
--- a/gdb/scm-lang.c
+++ b/gdb/scm-lang.c
@@ -267,6 +267,7 @@ const struct language_defn scm_language_defn =
default_word_break_characters,
c_language_arch_info,
default_print_array_index,
+ default_pass_by_reference,
LANG_MAGIC
};
diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog
index 8b30f8c..ae563f5 100644
--- a/gdb/testsuite/ChangeLog
+++ b/gdb/testsuite/ChangeLog
@@ -1,3 +1,7 @@
+2007-09-23 Daniel Jacobowitz <dan@codesourcery.com>
+
+ * gdb.cp/pass-by-ref.cc, gdb.cp/pass-by-ref.exp: New files.
+
2007-09-23 Pedro Alves <pedro_alves@portugalmail.pt>
* configure.ac: Do gdb.stabs tests by default on Cygwin and MinGW
diff --git a/gdb/testsuite/gdb.cp/pass-by-ref.cc b/gdb/testsuite/gdb.cp/pass-by-ref.cc
new file mode 100644
index 0000000..2a34b36
--- /dev/null
+++ b/gdb/testsuite/gdb.cp/pass-by-ref.cc
@@ -0,0 +1,79 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright 2007 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+class Obj {
+public:
+ Obj ();
+ Obj (const Obj &);
+ ~Obj ();
+ int var[2];
+};
+
+int foo (Obj arg)
+{
+ return arg.var[0] + arg.var[1];
+}
+
+Obj::Obj ()
+{
+ var[0] = 1;
+ var[1] = 2;
+}
+
+Obj::Obj (const Obj &obj)
+{
+ var[0] = obj.var[0];
+ var[1] = obj.var[1];
+}
+
+Obj::~Obj ()
+{
+
+}
+
+struct Derived : public Obj
+{
+ int other;
+};
+
+int blap (Derived arg)
+{
+ return foo (arg);
+}
+
+struct Container
+{
+ Obj obj;
+};
+
+int blip (Container arg)
+{
+ return foo (arg.obj);
+}
+
+Obj global_obj;
+Derived global_derived;
+Container global_container;
+
+int
+main ()
+{
+ int bar = foo (global_obj);
+ blap (global_derived);
+ blip (global_container);
+ return bar;
+}
diff --git a/gdb/testsuite/gdb.cp/pass-by-ref.exp b/gdb/testsuite/gdb.cp/pass-by-ref.exp
new file mode 100644
index 0000000..f218c82
--- /dev/null
+++ b/gdb/testsuite/gdb.cp/pass-by-ref.exp
@@ -0,0 +1,41 @@
+# Copyright 2007 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+# Check that GDB can call C++ functions whose parameters have
+# object type, but are passed by reference.
+
+if { [skip_cplus_tests] } { continue }
+
+set testfile "pass-by-ref"
+set srcfile ${testfile}.cc
+set binfile ${objdir}/${subdir}/${testfile}
+if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" \
+ executable {debug c++}] != "" } {
+ untested pass-by-ref.exp
+ return -1
+}
+
+gdb_exit
+gdb_start
+gdb_reinitialize_dir $srcdir/$subdir
+gdb_load ${binfile}
+
+if ![runto_main] then {
+ return -1
+}
+
+gdb_test "print foo (global_obj)" " = 3" "call function in obj"
+gdb_test "print blap (global_derived)" " = 3" "call function in derived"
+gdb_test "print blip (global_container)" " = 3" "call function in container"