aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Mitchell <mark@codesourcery.com>1999-09-25 18:10:04 +0000
committerMark Mitchell <mmitchel@gcc.gnu.org>1999-09-25 18:10:04 +0000
commitefee38a99ac1639e29a1f08235756becdbeca01c (patch)
tree29d37f53a0796acd0b38eaf7a9a35991a1aa4bf6
parent5a657fc371aefb7648ad42cc9db9187032a80809 (diff)
downloadgcc-efee38a99ac1639e29a1f08235756becdbeca01c.zip
gcc-efee38a99ac1639e29a1f08235756becdbeca01c.tar.gz
gcc-efee38a99ac1639e29a1f08235756becdbeca01c.tar.bz2
cp-tree.h (check_return_expr): New function.
* cp-tree.h (check_return_expr): New function. * decl.c (finish_constructor_body): New function. (pushdecl): Put global friend functions in namespace binding level, not the class binding level. (finish_destructor_body): Make sure the dtor_label is always defined. Fix typo in comment. (finish_function): Move generation of constructor-termination code to semantic-analysis time. Move generation of implicit `main' return value to semantic-analysis time. * semantics.c (finish_return_stmt): Generate goto's to ctor_label/dtor_label here. Use check_return_expr to do semantic analysis on the returned expression. * typeck.c (maybe_warn_about_returning_address_of_local): New function split out from c_expand_return. (check_return_expr): Likewise. (c_expand_return): Just generate the RTL for the return. From-SVN: r29663
-rw-r--r--gcc/cp/ChangeLog19
-rw-r--r--gcc/cp/cp-tree.h1
-rw-r--r--gcc/cp/decl.c67
-rw-r--r--gcc/cp/semantics.c27
-rw-r--r--gcc/cp/typeck.c336
5 files changed, 266 insertions, 184 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 19485a5..0efaa14 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,22 @@
+1999-09-25 Mark Mitchell <mark@codesourcery.com>
+
+ * cp-tree.h (check_return_expr): New function.
+ * decl.c (finish_constructor_body): New function.
+ (pushdecl): Put global friend functions in namespace binding
+ level, not the class binding level.
+ (finish_destructor_body): Make sure the dtor_label is always
+ defined. Fix typo in comment.
+ (finish_function): Move generation of constructor-termination code
+ to semantic-analysis time. Move generation of implicit `main'
+ return value to semantic-analysis time.
+ * semantics.c (finish_return_stmt): Generate goto's to
+ ctor_label/dtor_label here. Use check_return_expr to do semantic
+ analysis on the returned expression.
+ * typeck.c (maybe_warn_about_returning_address_of_local): New
+ function split out from c_expand_return.
+ (check_return_expr): Likewise.
+ (c_expand_return): Just generate the RTL for the return.
+
1999-09-24 Mark Mitchell <mark@codesourcery.com>
* cp-tree.h (CPTI_CLEANUP_TYPE): New macro.
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 584600e..15c5099 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -3949,6 +3949,7 @@ extern tree pfn_from_ptrmemfunc PROTO((tree));
extern tree type_after_usual_arithmetic_conversions PROTO((tree, tree));
extern tree composite_pointer_type PROTO((tree, tree, tree, tree,
const char*));
+extern tree check_return_expr PROTO((tree));
/* in typeck2.c */
extern tree error_not_base_type PROTO((tree, tree));
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index f456dbb..d5da38f 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -180,6 +180,7 @@ static void save_function_data PROTO((tree));
static void check_function_type PROTO((tree));
static void destroy_local_static PROTO((tree));
static void destroy_local_var PROTO((tree));
+static void finish_constructor_body PROTO((void));
static void finish_destructor_body PROTO((void));
#if defined (DEBUG_CP_BINDING_LEVELS)
@@ -4064,7 +4065,10 @@ pushdecl (x)
}
if (need_new_binding)
- add_decl_to_level (x, current_binding_level);
+ add_decl_to_level (x,
+ DECL_NAMESPACE_SCOPE_P (x)
+ ? NAMESPACE_LEVEL (CP_DECL_CONTEXT (x))
+ : current_binding_level);
return x;
}
@@ -13329,9 +13333,26 @@ save_function_data (decl)
f->cannot_inline = current_function_cannot_inline;
}
+/* At the end of every constructor we generate to code to return
+ `this'. Do that now. */
+
+static void
+finish_constructor_body ()
+{
+ /* Any return from a constructor will end up here. */
+ add_tree (build_min_nt (LABEL_STMT, ctor_label));
+
+ /* Clear CTOR_LABEL so that finish_return_stmt knows to really
+ generate the return, rather than a goto to CTOR_LABEL. */
+ ctor_label = NULL_TREE;
+ /* In check_return_expr we translate an empty return from a
+ constructor to a return of `this'. */
+ finish_return_stmt (NULL_TREE);
+}
+
/* At the end of every destructor we generate code to restore virtual
function tables to the values desired by base classes and to call
- to base class destructors. Do that now, for DECL. */
+ to base class destructors. Do that now. */
static void
finish_destructor_body ()
@@ -13344,6 +13365,9 @@ finish_destructor_body ()
/* Create a block to contain all the extra code. */
compound_stmt = begin_compound_stmt (/*has_no_scope=*/0);
+ /* Any return from a destructor will end up here. */
+ add_tree (build_min_nt (LABEL_STMT, dtor_label));
+
/* Generate the code to call destructor on base class. If this
destructor belongs to a class with virtual functions, then set
the virtual function table pointer to represent the type of our
@@ -13372,13 +13396,12 @@ finish_destructor_body ()
|| TREE_OPERAND (exprstmt, 0) != integer_zero_node
|| TYPE_USES_VIRTUAL_BASECLASSES (current_class_type)))
{
- add_tree (build_min_nt (LABEL_STMT, dtor_label));
if (exprstmt != void_zero_node)
/* Don't call `expand_expr_stmt' if we're not going to do
anything, since -Wall will give a diagnostic. */
finish_expr_stmt (exprstmt);
- /* Run destructor on all virtual baseclasses. */
+ /* Run destructors for all virtual baseclasses. */
if (TYPE_USES_VIRTUAL_BASECLASSES (current_class_type))
{
tree vbases = nreverse (copy_list (CLASSTYPE_VBASECLASSES (current_class_type)));
@@ -13496,10 +13519,23 @@ finish_function (lineno, flags)
if (building_stmt_tree ())
{
- if (DECL_CONSTRUCTOR_P (fndecl) && call_poplevel)
- do_poplevel ();
+ if (DECL_CONSTRUCTOR_P (fndecl))
+ {
+ finish_constructor_body ();
+ if (call_poplevel)
+ do_poplevel ();
+ }
else if (DECL_DESTRUCTOR_P (fndecl) && !processing_template_decl)
finish_destructor_body ();
+ else if (DECL_MAIN_P (fndecl))
+ {
+ /* Make it so that `main' always returns 0 by default. */
+#ifdef VMS
+ finish_return_stmt (integer_one_node);
+#else
+ finish_return_stmt (integer_zero_node);
+#endif
+ }
/* Finish dealing with exception specifiers. */
if (flag_exceptions && !processing_template_decl
@@ -13535,28 +13571,11 @@ finish_function (lineno, flags)
;
else if (DECL_CONSTRUCTOR_P (fndecl))
{
- /* This is where the body of the constructor begins. All
- subobjects have been fully constructed at this point. */
+ /* All subobjects have been fully constructed at this point. */
end_protect_partials ();
- /* This is where the body of the constructor ends. */
- expand_label (ctor_label);
- ctor_label = NULL_TREE;
-
if (call_poplevel)
do_poplevel ();
-
- /* c_expand_return knows to return 'this' from a constructor. */
- c_expand_return (NULL_TREE);
- }
- else if (DECL_MAIN_P (fndecl))
- {
- /* Make it so that `main' always returns 0 by default. */
-#ifdef VMS
- c_expand_return (integer_one_node);
-#else
- c_expand_return (integer_zero_node);
-#endif
}
else if (return_label != NULL_RTX
&& flag_this_is_variable <= 0
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index cd48570..ac7856b 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -371,6 +371,33 @@ void
finish_return_stmt (expr)
tree expr;
{
+ if (doing_semantic_analysis_p () && !processing_template_decl)
+ expr = check_return_expr (expr);
+
+ if (doing_semantic_analysis_p () && !processing_template_decl)
+ {
+ if (DECL_CONSTRUCTOR_P (current_function_decl) && ctor_label)
+ {
+ /* Even returns without a value in a constructor must return
+ `this'. We accomplish this by sending all returns in a
+ constructor to the CTOR_LABEL; finish_function emits code to
+ return a value there. When we finally generate the real
+ return statement, CTOR_LABEL is no longer set, and we fall
+ through into the normal return-processing code below. */
+ finish_goto_stmt (ctor_label);
+ return;
+ }
+ else if (DECL_DESTRUCTOR_P (current_function_decl))
+ {
+ /* Similarly, all destructors must run destructors for
+ base-classes before returning. So, all returns in a
+ destructor get sent to the DTOR_LABEL; finsh_function emits
+ code to return a value there. */
+ finish_goto_stmt (dtor_label);
+ return;
+ }
+ }
+
if (building_stmt_tree ())
add_tree (build_min_nt (RETURN_STMT, expr));
else
diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
index 80be5f8..6a18b11 100644
--- a/gcc/cp/typeck.c
+++ b/gcc/cp/typeck.c
@@ -64,6 +64,7 @@ static tree get_delta_difference PROTO((tree, tree, int));
static int comp_cv_target_types PROTO((tree, tree, int));
static void casts_away_constness_r PROTO((tree *, tree *));
static int casts_away_constness PROTO ((tree, tree));
+static void maybe_warn_about_returning_address_of_local PROTO ((tree));
/* Return the target type of TYPE, which means return T for:
T*, T&, T[], T (...), and otherwise, just T. */
@@ -6639,41 +6640,103 @@ c_expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
emit_queue ();
}
-/* Expand a C `return' statement.
- RETVAL is the expression for what to return,
- or a null pointer for `return;' with no value.
+/* If RETVAL is the address of, or a reference to, a local variable or
+ temporary give an appropraite warning. */
- C++: upon seeing a `return', we must call destructors on all
- variables in scope which had constructors called on them.
- This means that if in a destructor, the base class destructors
- must be called before returning.
+static void
+maybe_warn_about_returning_address_of_local (retval)
+ tree retval;
+{
+ tree valtype = TREE_TYPE (DECL_RESULT (current_function_decl));
- The RETURN statement in C++ has initialization semantics. */
+ if (TREE_CODE (valtype) == REFERENCE_TYPE)
+ {
+ tree whats_returned;
-void
-c_expand_return (retval)
+ /* Sort through common things to see what it is
+ we are returning. */
+ whats_returned = retval;
+ if (TREE_CODE (whats_returned) == COMPOUND_EXPR)
+ {
+ whats_returned = TREE_OPERAND (whats_returned, 1);
+ if (TREE_CODE (whats_returned) == ADDR_EXPR)
+ whats_returned = TREE_OPERAND (whats_returned, 0);
+ }
+ while (TREE_CODE (whats_returned) == CONVERT_EXPR
+ || TREE_CODE (whats_returned) == NOP_EXPR)
+ whats_returned = TREE_OPERAND (whats_returned, 0);
+ if (TREE_CODE (whats_returned) == ADDR_EXPR)
+ {
+ whats_returned = TREE_OPERAND (whats_returned, 0);
+ while (TREE_CODE (whats_returned) == AGGR_INIT_EXPR
+ || TREE_CODE (whats_returned) == TARGET_EXPR)
+ {
+ /* Get the target. */
+ whats_returned = TREE_OPERAND (whats_returned, 0);
+ warning ("returning reference to temporary");
+ }
+ }
+
+ if (TREE_CODE (whats_returned) == VAR_DECL
+ && DECL_NAME (whats_returned))
+ {
+ if (TEMP_NAME_P (DECL_NAME (whats_returned)))
+ warning ("reference to non-lvalue returned");
+ else if (TREE_CODE (TREE_TYPE (whats_returned)) != REFERENCE_TYPE
+ && DECL_FUNCTION_SCOPE_P (whats_returned)
+ && !(TREE_STATIC (whats_returned)
+ || TREE_PUBLIC (whats_returned)))
+ cp_warning_at ("reference to local variable `%D' returned",
+ whats_returned);
+ }
+ }
+ else if (TREE_CODE (retval) == ADDR_EXPR)
+ {
+ tree whats_returned = TREE_OPERAND (retval, 0);
+
+ if (TREE_CODE (whats_returned) == VAR_DECL
+ && DECL_NAME (whats_returned)
+ && DECL_FUNCTION_SCOPE_P (whats_returned)
+ && !(TREE_STATIC (whats_returned)
+ || TREE_PUBLIC (whats_returned)))
+ cp_warning_at ("address of local variable `%D' returned",
+ whats_returned);
+ }
+}
+
+/* Check that returning RETVAL from the current function is legal.
+ Return an expression explicitly showing all conversions required to
+ change RETVAL into the function return type, and to assign it to
+ the DECL_RESULT for the function. */
+
+tree
+check_return_expr (retval)
tree retval;
{
- tree result = DECL_RESULT (current_function_decl);
- tree valtype = TREE_TYPE (result);
-
+ tree result;
+ /* The type actually returned by the function, after any
+ promotions. */
+ tree valtype;
+ int fn_returns_value_p;
+
+ /* A `volatile' function is one that isn't supposed to return, ever.
+ (This is a G++ extension, used to get better code for functions
+ that call the `volatile' function.) */
if (TREE_THIS_VOLATILE (current_function_decl))
warning ("function declared `noreturn' has a `return' statement");
+ /* Check for various simple errors. */
if (retval == error_mark_node)
{
+ /* If an error occurred, there's nothing to do. */
current_function_returns_null = 1;
- return;
+ return error_mark_node;
}
-
- if (dtor_label)
+ else if (dtor_label)
{
if (retval)
error ("returning a value from a destructor");
-
- /* Can't just return from a destructor. */
- expand_goto (dtor_label);
- return;
+ return NULL_TREE;
}
else if (in_function_try_handler
&& DECL_CONSTRUCTOR_P (current_function_decl))
@@ -6681,8 +6744,57 @@ c_expand_return (retval)
/* If a return statement appears in a handler of the
function-try-block of a constructor, the program is ill-formed. */
error ("cannot return from a handler of a function-try-block of a constructor");
- return;
+ return error_mark_node;
+ }
+ else if (retval && DECL_CONSTRUCTOR_P (current_function_decl))
+ /* You can't return a value from a constructor. */
+ error ("returning a value from a constructor");
+
+ /* Constructors actually always return `this', even though in C++
+ you can't return a value from a constructor. */
+ if (DECL_CONSTRUCTOR_P (current_function_decl))
+ retval = current_class_ptr;
+
+ /* When no explicit return-value is given in a function with a named
+ return value, the named return value is used. */
+ result = DECL_RESULT (current_function_decl);
+ valtype = TREE_TYPE (result);
+ my_friendly_assert (valtype != NULL_TREE, 19990924);
+ fn_returns_value_p = !same_type_p (valtype, void_type_node);
+ if (!retval && DECL_NAME (result) && fn_returns_value_p)
+ retval = result;
+
+ /* Check for a return statement with no return value in a function
+ that's supposed to return a value. */
+ if (!retval && fn_returns_value_p)
+ {
+ pedwarn ("`return' with no value, in function returning non-void");
+ /* Clear this, so finish_function won't say that we reach the
+ end of a non-void function (which we don't, we gave a
+ return!). */
+ current_function_returns_null = 0;
+ }
+ /* Check for a return statement with a value in a function that
+ isn't supposed to return a value. */
+ else if (retval && !fn_returns_value_p)
+ {
+ if (same_type_p (TREE_TYPE (retval), void_type_node))
+ /* You can return a `void' value from a function of `void'
+ type. In that case, we have to evaluate the expression for
+ its side-effects. */
+ finish_expr_stmt (retval);
+ else
+ pedwarn ("`return' with a value, in function returning void");
+
+ current_function_returns_null = 1;
+
+ /* There's really no value to return, after all. */
+ return NULL_TREE;
}
+ else if (!retval)
+ /* Remember that this function can sometimes return without a
+ value. */
+ current_function_returns_null = 1;
/* Only operator new(...) throw(), can return NULL [expr.new/13]. */
if ((DECL_NAME (current_function_decl) == ansi_opname[(int) NEW_EXPR]
@@ -6690,41 +6802,6 @@ c_expand_return (retval)
&& !TYPE_NOTHROW_P (TREE_TYPE (current_function_decl))
&& null_ptr_cst_p (retval))
cp_warning ("operator new should throw an exception, not return NULL");
-
- if (retval == NULL_TREE)
- {
- /* A non-named return value does not count. */
-
- if (DECL_CONSTRUCTOR_P (current_function_decl))
- retval = current_class_ptr;
- else if (DECL_NAME (result) != NULL_TREE
- && TREE_CODE (valtype) != VOID_TYPE)
- retval = result;
- else
- {
- current_function_returns_null = 1;
-
- if (valtype != NULL_TREE && TREE_CODE (valtype) != VOID_TYPE)
- {
- if (DECL_NAME (DECL_RESULT (current_function_decl)) == NULL_TREE)
- {
- pedwarn ("`return' with no value, in function returning non-void");
- /* Clear this, so finish_function won't say that we
- reach the end of a non-void function (which we don't,
- we gave a return!). */
- current_function_returns_null = 0;
- }
- }
-
- expand_null_return ();
- return;
- }
- }
- else if (DECL_CONSTRUCTOR_P (current_function_decl))
- {
- error ("returning a value from a constructor");
- retval = current_class_ptr;
- }
/* Effective C++ rule 15. See also start_function. */
if (warn_ecpp
@@ -6732,137 +6809,76 @@ c_expand_return (retval)
&& retval != current_class_ref)
cp_warning ("`operator=' should return a reference to `*this'");
- if (valtype == NULL_TREE || TREE_CODE (valtype) == VOID_TYPE)
- {
- current_function_returns_null = 1;
- if (TREE_CODE (TREE_TYPE (retval)) != VOID_TYPE)
- pedwarn ("`return' with a value, in function returning void");
- expand_return (retval);
- return;
- }
-
- /* Now deal with possible C++ hair:
- (1) Compute the return value.
- (2) If there are aggregate values with destructors which
- must be cleaned up, clean them (taking care
- not to clobber the return value).
- (3) If an X(X&) constructor is defined, the return
- value must be returned via that. */
-
- if (retval == result
- || DECL_CONSTRUCTOR_P (current_function_decl))
- /* It's already done for us. */;
- else if (TREE_CODE (TREE_TYPE (retval)) == VOID_TYPE)
- {
- pedwarn ("return of void value in function returning non-void");
- expand_expr_stmt (retval);
- retval = 0;
- }
+ /* We don't need to do any conversions when there's nothing being
+ returned. */
+ if (!retval)
+ return NULL_TREE;
+
+ /* Do any required conversions. */
+ if (retval == result || DECL_CONSTRUCTOR_P (current_function_decl))
+ /* No conversions are required. */
+ ;
else
{
+ /* The type the function is declared to return. */
tree functype = TREE_TYPE (TREE_TYPE (current_function_decl));
/* First convert the value to the function's return type, then
to the type of return value's location to handle the
case that functype is thiner than the valtype. */
-
retval = convert_for_initialization
(NULL_TREE, functype, retval, LOOKUP_NORMAL|LOOKUP_ONLYCONVERTING,
"return", NULL_TREE, 0);
-
retval = convert (valtype, retval);
+ /* If the conversion failed, treat this just like `return;'. */
if (retval == error_mark_node)
- {
- /* Avoid warning about control reaching end of function. */
- expand_null_return ();
- return;
- }
-
+ return NULL_TREE;
/* We can't initialize a register from a AGGR_INIT_EXPR. */
else if (! current_function_returns_struct
&& TREE_CODE (retval) == TARGET_EXPR
&& TREE_CODE (TREE_OPERAND (retval, 1)) == AGGR_INIT_EXPR)
retval = build (COMPOUND_EXPR, TREE_TYPE (retval), retval,
TREE_OPERAND (retval, 0));
-
- /* Add some useful error checking for C++. */
- else if (TREE_CODE (valtype) == REFERENCE_TYPE)
- {
- tree whats_returned;
-
- /* Sort through common things to see what it is
- we are returning. */
- whats_returned = retval;
- if (TREE_CODE (whats_returned) == COMPOUND_EXPR)
- {
- whats_returned = TREE_OPERAND (whats_returned, 1);
- if (TREE_CODE (whats_returned) == ADDR_EXPR)
- whats_returned = TREE_OPERAND (whats_returned, 0);
- }
- while (TREE_CODE (whats_returned) == CONVERT_EXPR
- || TREE_CODE (whats_returned) == NOP_EXPR)
- whats_returned = TREE_OPERAND (whats_returned, 0);
- if (TREE_CODE (whats_returned) == ADDR_EXPR)
- {
- whats_returned = TREE_OPERAND (whats_returned, 0);
- while (TREE_CODE (whats_returned) == AGGR_INIT_EXPR
- || TREE_CODE (whats_returned) == TARGET_EXPR)
- {
- /* Get the target. */
- whats_returned = TREE_OPERAND (whats_returned, 0);
- warning ("returning reference to temporary");
- }
- }
-
- if (TREE_CODE (whats_returned) == VAR_DECL && DECL_NAME (whats_returned))
- {
- if (TEMP_NAME_P (DECL_NAME (whats_returned)))
- warning ("reference to non-lvalue returned");
- else if (TREE_CODE (TREE_TYPE (whats_returned)) != REFERENCE_TYPE
- && DECL_FUNCTION_SCOPE_P (whats_returned)
- && !(TREE_STATIC (whats_returned)
- || TREE_PUBLIC (whats_returned)))
- cp_warning_at ("reference to local variable `%D' returned", whats_returned);
- }
- }
- else if (TREE_CODE (retval) == ADDR_EXPR)
- {
- tree whats_returned = TREE_OPERAND (retval, 0);
-
- if (TREE_CODE (whats_returned) == VAR_DECL
- && DECL_NAME (whats_returned)
- && DECL_FUNCTION_SCOPE_P (whats_returned)
- && !(TREE_STATIC (whats_returned)
- || TREE_PUBLIC (whats_returned)))
- cp_warning_at ("address of local variable `%D' returned", whats_returned);
- }
- }
-
- if (retval != NULL_TREE
- && TREE_CODE_CLASS (TREE_CODE (retval)) == 'd'
- && ! in_control_zone_p ())
- current_function_return_value = retval;
-
- if (ctor_label && TREE_CODE (ctor_label) != ERROR_MARK)
- {
- /* Here RETVAL is CURRENT_CLASS_PTR, so there's nothing to do. */
- expand_goto (ctor_label);
+ else
+ maybe_warn_about_returning_address_of_local (retval);
}
-
+
+ /* Actually copy the value returned into the appropriate location. */
if (retval && retval != result)
{
- result = build (INIT_EXPR, TREE_TYPE (result), result, retval);
- TREE_SIDE_EFFECTS (result) = 1;
+ retval = build (INIT_EXPR, TREE_TYPE (result), result, retval);
+ TREE_SIDE_EFFECTS (retval) = 1;
}
- expand_start_target_temps ();
+ /* All done. Remember that this function did return a value. */
+ current_function_returns_value = 1;
+ return retval;
+}
+
+/* Expand a C `return' statement.
+ RETVAL is the expression for what to return,
+ or a null pointer for `return;' with no value.
- expand_return (result);
+ C++: upon seeing a `return', we must call destructors on all
+ variables in scope which had constructors called on them.
+ This means that if in a destructor, the base class destructors
+ must be called before returning.
- expand_end_target_temps ();
+ The RETURN statement in C++ has initialization semantics. */
- current_function_returns_value = 1;
+void
+c_expand_return (retval)
+ tree retval;
+{
+ if (!retval)
+ expand_null_return ();
+ else
+ {
+ expand_start_target_temps ();
+ expand_return (retval);
+ expand_end_target_temps ();
+ }
}
/* Start a C switch statement, testing expression EXP.