@@ -1695,6 +1695,7 @@ class ExprVisitor : public Visitor
16951695
16961696 tree callee = NULL_TREE;
16971697 tree object = NULL_TREE;
1698+ tree cleanup = NULL_TREE;
16981699 TypeFunction *tf = NULL ;
16991700
17001701 /* Calls to delegates can sometimes look like this. */
@@ -1732,6 +1733,19 @@ class ExprVisitor : public Visitor
17321733 {
17331734 tree thisexp = build_expr (dve->e1 );
17341735
1736+ /* When constructing temporaries, if the constructor throws,
1737+ then the object is destructed even though it is not a fully
1738+ constructed object yet. And so this call will need to be
1739+ moved inside the TARGET_EXPR_INITIAL slot. */
1740+ if (fd->isCtorDeclaration ()
1741+ && TREE_CODE (thisexp) == COMPOUND_EXPR
1742+ && TREE_CODE (TREE_OPERAND (thisexp, 0 )) == TARGET_EXPR
1743+ && TARGET_EXPR_CLEANUP (TREE_OPERAND (thisexp, 0 )))
1744+ {
1745+ cleanup = TREE_OPERAND (thisexp, 0 );
1746+ thisexp = TREE_OPERAND (thisexp, 1 );
1747+ }
1748+
17351749 /* Want reference to 'this' object. */
17361750 if (!POINTER_TYPE_P (TREE_TYPE (thisexp)))
17371751 thisexp = build_address (thisexp);
@@ -1820,6 +1834,20 @@ class ExprVisitor : public Visitor
18201834 if (e->type ->isTypeBasic ())
18211835 exp = d_convert (build_ctype (e->type ), exp);
18221836
1837+ /* If this call was found to be a constructor for a temporary with a
1838+ cleanup, then move the call inside the TARGET_EXPR. The original
1839+ initializer is turned into an assignment, to keep its side effect. */
1840+ if (cleanup != NULL_TREE)
1841+ {
1842+ tree init = TARGET_EXPR_INITIAL (cleanup);
1843+ tree slot = TARGET_EXPR_SLOT (cleanup);
1844+ d_mark_addressable (slot);
1845+ init = build_assign (INIT_EXPR, slot, init);
1846+
1847+ TARGET_EXPR_INITIAL (cleanup) = compound_expr (init, exp);
1848+ exp = cleanup;
1849+ }
1850+
18231851 this ->result_ = exp;
18241852 }
18251853
@@ -2013,22 +2041,9 @@ class ExprVisitor : public Visitor
20132041 can cause an empty STMT_LIST here. This can causes problems
20142042 during gimplification. */
20152043 if (TREE_CODE (result) == STATEMENT_LIST && !STATEMENT_LIST_HEAD (result))
2016- this ->result_ = build_empty_stmt (input_location);
2017- else
2018- this ->result_ = result;
2019-
2020- /* Maybe put variable on list of things needing destruction. */
2021- VarDeclaration *vd = e->declaration ->isVarDeclaration ();
2022- if (vd != NULL )
2023- {
2024- if (!vd->isStatic () && !(vd->storage_class & STCmanifest)
2025- && !(vd->storage_class & (STCextern | STCtls | STCgshared)))
2026- {
2027- if (vd->needsScopeDtor ())
2028- d_function_chain->vars_in_scope .safe_push (vd);
2029- }
2030- }
2044+ result = build_empty_stmt (input_location);
20312045
2046+ this ->result_ = result;
20322047 }
20332048
20342049 /* Build a typeid expression. Returns an instance of class TypeInfo
@@ -3039,86 +3054,20 @@ build_expr (Expression *e, bool const_p)
30393054 return expr;
30403055}
30413056
3042- /* Build an expression that calls the destructors on all the variables
3043- going out of the scope between STARTI and ENDI. All destructors are
3044- executed in reverse order. */
3045-
3046- static tree
3047- build_dtor_list (size_t starti, size_t endi)
3048- {
3049- tree dtors = NULL_TREE;
3050-
3051- for (size_t i = starti; i != endi; ++i)
3052- {
3053- VarDeclaration *vd = d_function_chain->vars_in_scope [i];
3054- if (vd)
3055- {
3056- d_function_chain->vars_in_scope [i] = NULL ;
3057- tree t = build_expr (vd->edtor );
3058- dtors = compound_expr (t, dtors);
3059- }
3060- }
3061-
3062- return dtors;
3063- }
3064-
30653057/* Same as build_expr, but also calls destructors on any temporaries. */
30663058
30673059tree
30683060build_expr_dtor (Expression *e)
30693061{
30703062 /* Codegen can be improved by determining if no exceptions can be thrown
30713063 between the ctor and dtor, and eliminating the ctor and dtor. */
3072- size_t starti = d_function_chain->vars_in_scope . length ( );
3064+ size_t saved_vars = vec_safe_length ( d_function_chain->vars_in_scope );
30733065 tree result = build_expr (e);
3074- size_t endi = d_function_chain->vars_in_scope .length ();
30753066
3076- tree dtors = build_dtor_list (starti, endi);
3077-
3078- if (dtors != NULL_TREE)
3067+ if (saved_vars != vec_safe_length (d_function_chain->vars_in_scope ))
30793068 {
3080- /* Split comma expressions, so that only the result is maybe saved. */
3081- tree expr = stabilize_expr (&result);
3082-
3083- /* When constructing temporaries, if the constructor throws, then
3084- we don't want to run the destructor on the incomplete object. */
3085- CallExp *ce = (e->op == TOKcall) ? ((CallExp *) e) : NULL ;
3086- if (ce != NULL && ce->e1 ->op == TOKdotvar
3087- && ((DotVarExp *) ce->e1 )->var ->isCtorDeclaration ())
3088- {
3089- /* Extract the object from the ctor call, as it will be the same
3090- value as the returned result, just maybe without the side effects.
3091- Rewriting: ctor (&e1) => (ctor (&e1), e1) */
3092- expr = compound_expr (expr, result);
3093-
3094- if (INDIRECT_REF_P (result))
3095- result = build_deref (CALL_EXPR_ARG (TREE_OPERAND (result, 0 ), 0 ));
3096- else
3097- result = CALL_EXPR_ARG (result, 0 );
3098-
3099- return compound_expr (compound_expr (expr, dtors), result);
3100- }
3101-
3102- /* Extract the LHS from the assignment expression.
3103- Rewriting: (e1 = e2) => ((e1 = e2), e1) */
3104- if (TREE_CODE (result) == INIT_EXPR || TREE_CODE (result) == MODIFY_EXPR)
3105- {
3106- expr = compound_expr (expr, result);
3107- result = TREE_OPERAND (result, 0 );
3108- }
3109-
3110- /* If the result has side-effects, save the entire expression. */
3111- if (TREE_SIDE_EFFECTS (result))
3112- {
3113- /* Wrap expr and dtors in a try/finally expression. */
3114- result = d_save_expr (result);
3115- expr = build2 (TRY_FINALLY_EXPR, void_type_node,
3116- compound_expr (expr, result), dtors);
3117- }
3118- else
3119- expr = compound_expr (expr, dtors);
3120-
3121- return compound_expr (expr, result);
3069+ result = fold_build_cleanup_point_expr (TREE_TYPE (result), result);
3070+ vec_safe_truncate (d_function_chain->vars_in_scope , saved_vars);
31223071 }
31233072
31243073 return result;
@@ -3129,13 +3078,11 @@ build_expr_dtor (Expression *e)
31293078tree
31303079build_return_dtor (Expression *e, Type *type, TypeFunction *tf)
31313080{
3132- size_t starti = d_function_chain->vars_in_scope . length ( );
3081+ size_t saved_vars = vec_safe_length ( d_function_chain->vars_in_scope );
31333082 tree result = build_expr (e);
3134- size_t endi = d_function_chain->vars_in_scope .length ();
31353083
31363084 /* Convert for initialising the DECL_RESULT. */
31373085 result = convert_expr (result, e->type , type);
3138- tree dtors = build_dtor_list (starti, endi);
31393086
31403087 /* If we are returning a reference, take the address. */
31413088 if (tf->isref )
@@ -3149,9 +3096,12 @@ build_return_dtor (Expression *e, Type *type, TypeFunction *tf)
31493096 result = build_assign (INIT_EXPR, decl, result);
31503097 result = compound_expr (expr, return_expr (result));
31513098
3152- /* Nest the return expression inside the try/finally expression. */
3153- if (dtors != NULL_TREE)
3154- return build2 (TRY_FINALLY_EXPR, void_type_node, result, dtors);
3099+ /* May nest the return expression inside the try/finally expression. */
3100+ if (saved_vars != vec_safe_length (d_function_chain->vars_in_scope ))
3101+ {
3102+ result = fold_build_cleanup_point_expr (TREE_TYPE (result), result);
3103+ vec_safe_truncate (d_function_chain->vars_in_scope , saved_vars);
3104+ }
31553105
31563106 return result;
31573107}
0 commit comments