aboutsummaryrefslogtreecommitdiff
path: root/gcc/cp/decl.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/cp/decl.c')
-rw-r--r--gcc/cp/decl.c77
1 files changed, 55 insertions, 22 deletions
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 8c85e71..0f48997 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -100,7 +100,6 @@ static tree check_initializer (tree, tree, int, tree *);
static void make_rtl_for_nonlocal_decl (tree, tree, const char *);
static void save_function_data (tree);
static void check_function_type (tree, tree);
-static void begin_constructor_body (void);
static void finish_constructor_body (void);
static void begin_destructor_body (void);
static void finish_destructor_body (void);
@@ -6182,7 +6181,8 @@ create_array_type_for_decl (tree name, tree type, tree size)
/* Check that it's OK to declare a function with the indicated TYPE.
SFK indicates the kind of special function (if any) that this
function is. OPTYPE is the type given in a conversion operator
- declaration. Returns the actual return type of the function; that
+ declaration, or the class type for a constructor/destructor.
+ Returns the actual return type of the function; that
may be different than TYPE if an error occurs, or for certain
special functions. */
@@ -6197,13 +6197,23 @@ check_special_function_return_type (special_function_kind sfk,
if (type)
error ("return type specification for constructor invalid");
- type = void_type_node;
+ if (targetm.cxx.cdtor_returns_this () && !TYPE_FOR_JAVA (optype))
+ type = build_pointer_type (optype);
+ else
+ type = void_type_node;
break;
case sfk_destructor:
if (type)
error ("return type specification for destructor invalid");
- type = void_type_node;
+ /* We can't use the proper return type here because we run into
+ problems with abiguous bases and covariant returns.
+ Java classes are left unchanged because (void *) isn't a valid
+ Java type, and we don't want to change the Java ABI. */
+ if (targetm.cxx.cdtor_returns_this () && !TYPE_FOR_JAVA (optype))
+ type = build_pointer_type (void_type_node);
+ else
+ type = void_type_node;
break;
case sfk_conversion:
@@ -6589,6 +6599,9 @@ grokdeclarator (const cp_declarator *declarator,
typedef_type = type;
+ if (sfk != sfk_conversion)
+ ctor_return_type = ctype;
+
if (sfk != sfk_none)
type = check_special_function_return_type (sfk, type,
ctor_return_type);
@@ -9879,10 +9892,12 @@ start_preparsed_function (tree decl1, tree attrs, int flags)
++function_depth;
- if (DECL_DESTRUCTOR_P (decl1))
+ if (DECL_DESTRUCTOR_P (decl1)
+ || (DECL_CONSTRUCTOR_P (decl1)
+ && targetm.cxx.cdtor_returns_this ()))
{
- dtor_label = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE);
- DECL_CONTEXT (dtor_label) = current_function_decl;
+ cdtor_label = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE);
+ DECL_CONTEXT (cdtor_label) = current_function_decl;
}
start_fname_decls ();
@@ -10050,22 +10065,27 @@ save_function_data (tree decl)
f->x_local_names = NULL;
}
-/* Add a note to mark the beginning of the main body of the constructor.
- This is used to set up the data structures for the cleanup regions for
- fully-constructed bases and members. */
-static void
-begin_constructor_body (void)
-{
-}
-
-/* Add a note to mark the end of the main body of the constructor. This is
- used to end the cleanup regions for fully-constructed bases and
- members. */
+/* Set the return value of the constructor (if present). */
static void
finish_constructor_body (void)
{
+ tree val;
+ tree exprstmt;
+
+ if (targetm.cxx.cdtor_returns_this ())
+ {
+ /* Any return from a constructor will end up here. */
+ add_stmt (build_stmt (LABEL_EXPR, cdtor_label));
+
+ val = DECL_ARGUMENTS (current_function_decl);
+ val = build (MODIFY_EXPR, TREE_TYPE (val),
+ DECL_RESULT (current_function_decl), val);
+ /* Return the address of the object. */
+ exprstmt = build_stmt (RETURN_EXPR, val);
+ add_stmt (exprstmt);
+ }
}
/* Do all the processing for the beginning of a destructor; set up the
@@ -10125,7 +10145,7 @@ finish_destructor_body (void)
/* Any return from a destructor will end up here; that way all base
and member cleanups will be run when the function returns. */
- add_stmt (build_stmt (LABEL_EXPR, dtor_label));
+ add_stmt (build_stmt (LABEL_EXPR, cdtor_label));
/* In a virtual destructor, we must call delete. */
if (DECL_VIRTUAL_P (current_function_decl))
@@ -10152,6 +10172,18 @@ finish_destructor_body (void)
finish_then_clause (if_stmt);
finish_if_stmt (if_stmt);
}
+
+ if (targetm.cxx.cdtor_returns_this ())
+ {
+ tree val;
+
+ val = DECL_ARGUMENTS (current_function_decl);
+ val = build (MODIFY_EXPR, TREE_TYPE (val),
+ DECL_RESULT (current_function_decl), val);
+ /* Return the address of the object. */
+ exprstmt = build_stmt (RETURN_EXPR, val);
+ add_stmt (exprstmt);
+ }
}
/* Do the necessary processing for the beginning of a function body, which
@@ -10177,8 +10209,6 @@ begin_function_body (void)
if (processing_template_decl)
/* Do nothing now. */;
- else if (DECL_CONSTRUCTOR_P (current_function_decl))
- begin_constructor_body ();
else if (DECL_DESTRUCTOR_P (current_function_decl))
begin_destructor_body ();
@@ -10363,7 +10393,10 @@ finish_function (int flags)
&& !DECL_NAME (DECL_RESULT (fndecl))
/* Normally, with -Wreturn-type, flow will complain. Unless we're an
inline function, as we might never be compiled separately. */
- && (DECL_INLINE (fndecl) || processing_template_decl))
+ && (DECL_INLINE (fndecl) || processing_template_decl)
+ /* Structor return values (if any) are set by the compiler. */
+ && !DECL_CONSTRUCTOR_P (fndecl)
+ && !DECL_DESTRUCTOR_P (fndecl))
warning ("no return statement in function returning non-void");
/* Store the end of the function, so that we get good line number