This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
C++ PATCH: PR 11326
- From: Mark Mitchell <mark at codesourcery dot com>
- To: gcc-patches at gcc dot gnu dot org
- Date: Tue, 17 Feb 2004 10:42:13 -0800
- Subject: C++ PATCH: PR 11326
- Reply-to: mark at codesourcery dot com
This patch fixes PR c++/1326, an Itanium-specific bug in the C++ ABI.
The C++ ABI specifically requires that on Itanium the struture return
parameter for classes with non-trivial copy constructors or
destructors be passed in out0, rather than in r8, which is where it
passed otherwise. (The rationale for this, I believe, is to make it
easier to write C functions that implement C++ interfaces.)
HP's compiler correctly implements this rule.
Tested on ia64-hp-hpux11.22, applied on the mainline and on the 3.4
branch as soon as I finish testing the minor variations required
there.
--
Mark Mitchell
CodeSourcery, LLC
mark@codesourcery.com
2004-02-17 Mark Mitchell <mark@codesourcery.com>
PR c++/11326
* c-common.c (flag_abi_version): Remove.
* c-common.h (flag_abi_version): Likewise.
* c-opts.c (c_common_handle_option): Remove OPT_fabi_version case.
* c.opt (fabi-version): Remove.
* calls.c (expand_call): Always pass a function type to
struct_value_rtx. Use convert_memory_address.
* common.opt (fabi-version): Add it.
* flags.h (flag_abi_version): Likewise.
(abi_version_at_least): New macro.
* opts.c (common_handle_option): Add OPT_fabi_version.
* toplev.c (flag_abi_version): Define it.
* config/ia64/ia64.c (ia64_struct_retval_addr_is_first_parm_p):
New function.
(ia64_output_mi_thunk): Use it.
(ia64_struct_value_rtx): Likewise.
2004-02-17 Mark Mitchell <mark@codesourcery.com>
PR c++/11326
* cp-tree.h (abi_version_at_least): Remove.
* mangle.c: Include flags.h.
2004-02-17 Mark Mitchell <mark@codesourcery.com>
PR c++/11326
* g++.dg/abi/structret1.C: New test.
Index: c-common.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/c-common.c,v
retrieving revision 1.483
diff -c -5 -p -r1.483 c-common.c
*** c-common.c 11 Feb 2004 01:55:28 -0000 1.483
--- c-common.c 17 Feb 2004 18:13:13 -0000
*************** int flag_permissive;
*** 597,623 ****
doesn't match the specification. Zero means to treat them as
assertions and optimize accordingly, but not check them. */
int flag_enforce_eh_specs = 1;
- /* The version of the C++ ABI in use. The following values are
- allowed:
-
- 0: The version of the ABI believed most conformant with the
- C++ ABI specification. This ABI may change as bugs are
- discovered and fixed. Therefore, 0 will not necessarily
- indicate the same ABI in different versions of G++.
-
- 1: The version of the ABI first used in G++ 3.2.
-
- 2: The version of the ABI first used in G++ 3.4.
-
- Additional positive integers will be assigned as new versions of
- the ABI become the default version of the ABI. */
-
- int flag_abi_version = 2;
-
/* Nonzero means warn about things that will change when compiling
with an ABI-compliant compiler. */
int warn_abi = 0;
--- 597,606 ----
Index: c-common.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/c-common.h,v
retrieving revision 1.221
diff -c -5 -p -r1.221 c-common.h
*** c-common.h 15 Feb 2004 14:30:38 -0000 1.221
--- c-common.h 17 Feb 2004 18:13:14 -0000
*************** extern int flag_permissive;
*** 758,782 ****
doesn't match the specification. Zero means to treat them as
assertions and optimize accordingly, but not check them. */
extern int flag_enforce_eh_specs;
- /* The version of the C++ ABI in use. The following values are
- allowed:
-
- 0: The version of the ABI believed most conformant with the
- C++ ABI specification. This ABI may change as bugs are
- discovered and fixed. Therefore, 0 will not necessarily
- indicate the same ABI in different versions of G++.
-
- 1: The version of the ABI first used in G++ 3.2.
-
- Additional positive integers will be assigned as new versions of
- the ABI become the default version of the ABI. */
-
- extern int flag_abi_version;
-
/* Nonzero means warn about things that will change when compiling
with an ABI-compliant compiler. */
extern int warn_abi;
--- 758,767 ----
Index: c-opts.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/c-opts.c,v
retrieving revision 1.102
diff -c -5 -p -r1.102 c-opts.c
*** c-opts.c 10 Feb 2004 18:18:55 -0000 1.102
--- c-opts.c 17 Feb 2004 18:13:14 -0000
*************** c_common_handle_option (size_t scode, co
*** 690,703 ****
case OPT_fxref:
case OPT_fvtable_gc:
warning ("switch \"%s\" is no longer supported", option->opt_text);
break;
- case OPT_fabi_version_:
- flag_abi_version = value;
- break;
-
case OPT_faccess_control:
flag_access_control = value;
break;
case OPT_fasm:
--- 690,699 ----
Index: c.opt
===================================================================
RCS file: /cvs/gcc/gcc/gcc/c.opt,v
retrieving revision 1.18
diff -c -5 -p -r1.18 c.opt
*** c.opt 2 Feb 2004 20:20:49 -0000 1.18
--- c.opt 17 Feb 2004 18:13:14 -0000
*************** A synonym for -std=c89. In a future ver
*** 409,421 ****
d
C ObjC C++ ObjC++ Joined
; Documented in common.opt. FIXME - what about -dI, -dD, -dN and -dD?
- fabi-version=
- C++ ObjC++ Joined UInteger
-
faccess-control
C++ ObjC++
Enforce class member access control semantics
fall-virtual
--- 409,418 ----
Index: calls.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/calls.c,v
retrieving revision 1.319
diff -c -5 -p -r1.319 calls.c
*** calls.c 6 Feb 2004 06:18:11 -0000 1.319
--- calls.c 17 Feb 2004 18:13:16 -0000
*************** expand_call (tree exp, rtx target, int i
*** 2078,2087 ****
--- 2078,2089 ----
tree funtype;
tree type_arg_types;
/* Declaration of the function being called,
or 0 if the function is computed (not known by name). */
tree fndecl = 0;
+ /* The type of the function being called. */
+ tree fntype;
rtx insn;
int try_tail_call = 1;
int try_tail_recursion = 1;
int pass;
*************** expand_call (tree exp, rtx target, int i
*** 2186,2195 ****
--- 2188,2198 ----
As a result, decide whether this is a call to an integrable function. */
fndecl = get_callee_fndecl (exp);
if (fndecl)
{
+ fntype = TREE_TYPE (fndecl);
if (!flag_no_inline
&& fndecl != current_function_decl
&& DECL_INLINE (fndecl)
&& DECL_SAVED_INSNS (fndecl)
&& DECL_SAVED_INSNS (fndecl)->inlinable)
*************** expand_call (tree exp, rtx target, int i
*** 2221,2239 ****
/* If we don't have specific function to call, see if we have a
attributes set in the type. */
else
{
if (ignore
! && lookup_attribute ("warn_unused_result",
! TYPE_ATTRIBUTES (TREE_TYPE (TREE_TYPE (p)))))
warning ("ignoring return value of function "
"declared with attribute warn_unused_result");
! flags |= flags_from_decl_or_type (TREE_TYPE (TREE_TYPE (p)));
}
! struct_value = targetm.calls.struct_value_rtx (fndecl ? TREE_TYPE (fndecl) : 0, 0);
/* Warn if this value is an aggregate type,
regardless of which calling convention we are using for it. */
if (warn_aggregate_return && AGGREGATE_TYPE_P (TREE_TYPE (exp)))
warning ("function call has aggregate value");
--- 2224,2242 ----
/* If we don't have specific function to call, see if we have a
attributes set in the type. */
else
{
+ fntype = TREE_TYPE (TREE_TYPE (p));
if (ignore
! && lookup_attribute ("warn_unused_result", TYPE_ATTRIBUTES (fntype)))
warning ("ignoring return value of function "
"declared with attribute warn_unused_result");
! flags |= flags_from_decl_or_type (fntype);
}
! struct_value = targetm.calls.struct_value_rtx (fntype, 0);
/* Warn if this value is an aggregate type,
regardless of which calling convention we are using for it. */
if (warn_aggregate_return && AGGREGATE_TYPE_P (TREE_TYPE (exp)))
warning ("function call has aggregate value");
*************** expand_call (tree exp, rtx target, int i
*** 2383,2393 ****
register in some cases. */
rtx temp = (GET_CODE (structure_value_addr) != REG
|| (ACCUMULATE_OUTGOING_ARGS
&& stack_arg_under_construction
&& structure_value_addr == virtual_outgoing_args_rtx)
! ? copy_addr_to_reg (structure_value_addr)
: structure_value_addr);
actparms
= tree_cons (error_mark_node,
make_tree (build_pointer_type (TREE_TYPE (funtype)),
--- 2386,2397 ----
register in some cases. */
rtx temp = (GET_CODE (structure_value_addr) != REG
|| (ACCUMULATE_OUTGOING_ARGS
&& stack_arg_under_construction
&& structure_value_addr == virtual_outgoing_args_rtx)
! ? copy_addr_to_reg (convert_memory_address
! (Pmode, structure_value_addr))
: structure_value_addr);
actparms
= tree_cons (error_mark_node,
make_tree (build_pointer_type (TREE_TYPE (funtype)),
Index: common.opt
===================================================================
RCS file: /cvs/gcc/gcc/gcc/common.opt,v
retrieving revision 1.26
diff -c -5 -p -r1.26 common.opt
*** common.opt 6 Feb 2004 20:03:40 -0000 1.26
--- common.opt 17 Feb 2004 18:13:16 -0000
*************** fPIC
*** 177,186 ****
--- 177,189 ----
Common
fPIE
Common
+ fabi-version=
+ Common Joined UInteger
+
falign-functions
Common
Align the start of functions
falign-functions=
Index: flags.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/flags.h,v
retrieving revision 1.129
diff -c -5 -p -r1.129 flags.h
*** flags.h 6 Feb 2004 20:03:41 -0000 1.129
--- flags.h 17 Feb 2004 18:13:17 -0000
*************** extern int flag_var_tracking;
*** 729,738 ****
--- 729,759 ----
/* A string that's used when a random name is required. NULL means
to make it really random. */
extern const char *flag_random_seed;
+ /* The version of the C++ ABI in use. The following values are
+ allowed:
+
+ 0: The version of the ABI believed most conformant with the
+ C++ ABI specification. This ABI may change as bugs are
+ discovered and fixed. Therefore, 0 will not necessarily
+ indicate the same ABI in different versions of G++.
+
+ 1: The version of the ABI first used in G++ 3.2.
+
+ Additional positive integers will be assigned as new versions of
+ the ABI become the default version of the ABI. */
+
+ extern int flag_abi_version;
+
+ /* Returns TRUE if generated code should match ABI version N or
+ greater is in use. */
+
+ #define abi_version_at_least(N) \
+ (flag_abi_version == 0 || flag_abi_version >= (N))
+
/* True if the given mode has a NaN representation and the treatment of
NaN operands is important. Certain optimizations, such as folding
x * 0 into x, are not correct for NaN operands, and are normally
disabled for modes with NaNs. The user can ask for them to be
done anyway using the -funsafe-math-optimizations switch. */
Index: opts.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/opts.c,v
retrieving revision 1.54
diff -c -5 -p -r1.54 opts.c
*** opts.c 6 Feb 2004 20:03:42 -0000 1.54
--- opts.c 17 Feb 2004 18:13:17 -0000
*************** common_handle_option (size_t scode, cons
*** 831,840 ****
--- 831,844 ----
case OPT_fPIE:
flag_pie = value + value;
break;
+ case OPT_fabi_version_:
+ flag_abi_version = value;
+ break;
+
case OPT_falign_functions:
align_functions = !value;
break;
case OPT_falign_functions_:
Index: toplev.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/toplev.c,v
retrieving revision 1.876
diff -c -5 -p -r1.876 toplev.c
*** toplev.c 12 Feb 2004 21:42:26 -0000 1.876
--- toplev.c 17 Feb 2004 18:13:17 -0000
*************** int flag_wrapv = 0;
*** 1014,1023 ****
--- 1014,1040 ----
int flag_evaluation_order = 0;
/* Add or remove a leading underscore from user symbols. */
int flag_leading_underscore = -1;
+ /* The version of the C++ ABI in use. The following values are
+ allowed:
+
+ 0: The version of the ABI believed most conformant with the
+ C++ ABI specification. This ABI may change as bugs are
+ discovered and fixed. Therefore, 0 will not necessarily
+ indicate the same ABI in different versions of G++.
+
+ 1: The version of the ABI first used in G++ 3.2.
+
+ 2: The version of the ABI first used in G++ 3.4.
+
+ Additional positive integers will be assigned as new versions of
+ the ABI become the default version of the ABI. */
+
+ int flag_abi_version = 2;
+
/* The user symbol prefix after having resolved same. */
const char *user_label_prefix;
static const param_info lang_independent_params[] = {
#define DEFPARAM(ENUM, OPTION, HELP, DEFAULT) \
Index: config/ia64/ia64.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/ia64/ia64.c,v
retrieving revision 1.275
diff -c -5 -p -r1.275 ia64.c
*** config/ia64/ia64.c 15 Feb 2004 14:53:40 -0000 1.275
--- config/ia64/ia64.c 17 Feb 2004 18:13:19 -0000
*************** static unsigned int
*** 8800,8809 ****
--- 8800,8830 ----
ia64_rwreloc_section_type_flags (tree decl, const char *name, int reloc)
{
return default_section_type_flags_1 (decl, name, reloc, true);
}
+ /* Returns true if FNTYPE (a FUNCTION_TYPE or a METHOD_TYPE) returns a
+ structure type and that the address of that type should be passed
+ in out0, rather than in r8. */
+
+ static bool
+ ia64_struct_retval_addr_is_first_parm_p (tree fntype)
+ {
+ tree ret_type = TREE_TYPE (fntype);
+
+ /* The Itanium C++ ABI requires that out0, rather than r8, be used
+ as the structure return address parameter, if the return value
+ type has a non-trivial copy constructor or destructor. It is not
+ clear if this same convention should be used for other
+ programming languages. Until G++ 3.4, we incorrectly used r8 for
+ these return values. */
+ return (abi_version_at_least (2)
+ && ret_type
+ && TYPE_MODE (ret_type) == BLKmode
+ && TREE_ADDRESSABLE (ret_type)
+ && strcmp (lang_hooks.name, "GNU C++") == 0);
+ }
/* Output the assembler code for a thunk function. THUNK_DECL is the
declaration for the thunk function itself, FUNCTION is the decl for
the target function. DELTA is an immediate constant offset to be
added to THIS. If VCALL_OFFSET is nonzero, the word at
*************** static void
*** 8813,8822 ****
--- 8834,8845 ----
ia64_output_mi_thunk (FILE *file, tree thunk ATTRIBUTE_UNUSED,
HOST_WIDE_INT delta, HOST_WIDE_INT vcall_offset,
tree function)
{
rtx this, insn, funexp;
+ unsigned int this_parmno;
+ unsigned int this_regno;
reload_completed = 1;
epilogue_completed = 1;
no_new_pseudos = 1;
*************** ia64_output_mi_thunk (FILE *file, tree t
*** 8826,8845 ****
memset (¤t_frame_info, 0, sizeof (current_frame_info));
current_frame_info.spill_cfa_off = -16;
current_frame_info.n_input_regs = 1;
current_frame_info.need_regstk = (TARGET_REG_NAMES != 0);
- if (!TARGET_REG_NAMES)
- reg_names[IN_REG (0)] = ia64_reg_numbers[0];
-
/* Mark the end of the (empty) prologue. */
emit_note (NOTE_INSN_PROLOGUE_END);
! this = gen_rtx_REG (Pmode, IN_REG (0));
if (TARGET_ILP32)
{
! rtx tmp = gen_rtx_REG (ptr_mode, IN_REG (0));
REG_POINTER (tmp) = 1;
if (delta && CONST_OK_FOR_I (delta))
{
emit_insn (gen_ptr_extend_plus_imm (this, tmp, GEN_INT (delta)));
delta = 0;
--- 8849,8875 ----
memset (¤t_frame_info, 0, sizeof (current_frame_info));
current_frame_info.spill_cfa_off = -16;
current_frame_info.n_input_regs = 1;
current_frame_info.need_regstk = (TARGET_REG_NAMES != 0);
/* Mark the end of the (empty) prologue. */
emit_note (NOTE_INSN_PROLOGUE_END);
! /* Figure out whether "this" will be the first parameter (the
! typical case) or the second parameter (as happens when the
! virtual function returns certain class objects). */
! this_parmno
! = (ia64_struct_retval_addr_is_first_parm_p (TREE_TYPE (thunk))
! ? 1 : 0);
! this_regno = IN_REG (this_parmno);
! if (!TARGET_REG_NAMES)
! reg_names[this_regno] = ia64_reg_numbers[this_parmno];
!
! this = gen_rtx_REG (Pmode, this_regno);
if (TARGET_ILP32)
{
! rtx tmp = gen_rtx_REG (ptr_mode, this_regno);
REG_POINTER (tmp) = 1;
if (delta && CONST_OK_FOR_I (delta))
{
emit_insn (gen_ptr_extend_plus_imm (this, tmp, GEN_INT (delta)));
delta = 0;
*************** ia64_output_mi_thunk (FILE *file, tree t
*** 8943,8954 ****
}
/* Worker function for TARGET_STRUCT_VALUE_RTX. */
static rtx
! ia64_struct_value_rtx (tree fntype ATTRIBUTE_UNUSED,
int incoming ATTRIBUTE_UNUSED)
{
return gen_rtx_REG (Pmode, GR_REG (8));
}
#include "gt-ia64.h"
--- 8973,8986 ----
}
/* Worker function for TARGET_STRUCT_VALUE_RTX. */
static rtx
! ia64_struct_value_rtx (tree fntype,
int incoming ATTRIBUTE_UNUSED)
{
+ if (ia64_struct_retval_addr_is_first_parm_p (fntype))
+ return NULL_RTX;
return gen_rtx_REG (Pmode, GR_REG (8));
}
#include "gt-ia64.h"
Index: cp/cp-tree.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/cp-tree.h,v
retrieving revision 1.953
diff -c -5 -p -r1.953 cp-tree.h
*** cp/cp-tree.h 14 Feb 2004 00:49:12 -0000 1.953
--- cp/cp-tree.h 17 Feb 2004 18:13:20 -0000
*************** struct diagnostic_context;
*** 211,226 ****
#define RECORD_OR_UNION_TYPE_CHECK(NODE) (NODE)
#define BOUND_TEMPLATE_TEMPLATE_PARM_TYPE_CHECK(NODE) (NODE)
#endif
- /* Returns TRUE if generated code should match ABI version N or
- greater is in use. */
-
- #define abi_version_at_least(N) \
- (flag_abi_version == 0 || flag_abi_version >= (N))
-
/* Language-dependent contents of an identifier. */
struct lang_identifier GTY(())
{
--- 211,220 ----
Index: cp/mangle.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/mangle.c,v
retrieving revision 1.97
diff -c -5 -p -r1.97 mangle.c
*** cp/mangle.c 29 Jan 2004 16:47:12 -0000 1.97
--- cp/mangle.c 17 Feb 2004 18:13:20 -0000
***************
*** 56,65 ****
--- 56,66 ----
#include "cp-tree.h"
#include "real.h"
#include "obstack.h"
#include "toplev.h"
#include "varray.h"
+ #include "flags.h"
/* Debugging support. */
/* Define DEBUG_MANGLE to enable very verbose trace messages. */
#ifndef DEBUG_MANGLE
Index: testsuite/g++.dg/abi/structret1.C
===================================================================
RCS file: testsuite/g++.dg/abi/structret1.C
diff -N testsuite/g++.dg/abi/structret1.C
*** /dev/null 1 Jan 1970 00:00:00 -0000
--- testsuite/g++.dg/abi/structret1.C 17 Feb 2004 18:13:23 -0000
***************
*** 0 ****
--- 1,31 ----
+ // { dg-do run { target ia64-*-* } }
+ // { dg-options "-fabi-version=0" }
+
+ extern "C" void abort ();
+
+ struct ConstructedObject {
+ ConstructedObject() {};
+ ~ConstructedObject() {};
+ ConstructedObject(const ConstructedObject &from) {};
+ };
+
+ struct FrameworkObject {
+ ConstructedObject action();
+ };
+
+ ConstructedObject FrameworkObject::action() {
+ void *r32, *r33;
+
+ asm("mov %0 = r32\nmov %1 = r33" : "=r"(r32), "=r"(r33) : );
+ if (this != r33) {
+ abort ();
+ }
+ }
+
+ int main()
+ {
+ FrameworkObject slawa;
+ slawa.action();
+ return 0;
+ }
+