@@ -1695,6 +1695,7 @@ class ExprVisitor : public Visitor
1695
1695
1696
1696
tree callee = NULL_TREE;
1697
1697
tree object = NULL_TREE;
1698
+ tree cleanup = NULL_TREE;
1698
1699
TypeFunction *tf = NULL ;
1699
1700
1700
1701
/* Calls to delegates can sometimes look like this. */
@@ -1732,6 +1733,19 @@ class ExprVisitor : public Visitor
1732
1733
{
1733
1734
tree thisexp = build_expr (dve->e1 );
1734
1735
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
+
1735
1749
/* Want reference to 'this' object. */
1736
1750
if (!POINTER_TYPE_P (TREE_TYPE (thisexp)))
1737
1751
thisexp = build_address (thisexp);
@@ -1820,6 +1834,20 @@ class ExprVisitor : public Visitor
1820
1834
if (e->type ->isTypeBasic ())
1821
1835
exp = d_convert (build_ctype (e->type ), exp);
1822
1836
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
+
1823
1851
this ->result_ = exp;
1824
1852
}
1825
1853
@@ -2013,22 +2041,9 @@ class ExprVisitor : public Visitor
2013
2041
can cause an empty STMT_LIST here. This can causes problems
2014
2042
during gimplification. */
2015
2043
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);
2031
2045
2046
+ this ->result_ = result;
2032
2047
}
2033
2048
2034
2049
/* Build a typeid expression. Returns an instance of class TypeInfo
@@ -3039,86 +3054,20 @@ build_expr (Expression *e, bool const_p)
3039
3054
return expr;
3040
3055
}
3041
3056
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
-
3065
3057
/* Same as build_expr, but also calls destructors on any temporaries. */
3066
3058
3067
3059
tree
3068
3060
build_expr_dtor (Expression *e)
3069
3061
{
3070
3062
/* Codegen can be improved by determining if no exceptions can be thrown
3071
3063
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 );
3073
3065
tree result = build_expr (e);
3074
- size_t endi = d_function_chain->vars_in_scope .length ();
3075
3066
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 ))
3079
3068
{
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);
3122
3071
}
3123
3072
3124
3073
return result;
@@ -3129,13 +3078,11 @@ build_expr_dtor (Expression *e)
3129
3078
tree
3130
3079
build_return_dtor (Expression *e, Type *type, TypeFunction *tf)
3131
3080
{
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 );
3133
3082
tree result = build_expr (e);
3134
- size_t endi = d_function_chain->vars_in_scope .length ();
3135
3083
3136
3084
/* Convert for initialising the DECL_RESULT. */
3137
3085
result = convert_expr (result, e->type , type);
3138
- tree dtors = build_dtor_list (starti, endi);
3139
3086
3140
3087
/* If we are returning a reference, take the address. */
3141
3088
if (tf->isref )
@@ -3149,9 +3096,12 @@ build_return_dtor (Expression *e, Type *type, TypeFunction *tf)
3149
3096
result = build_assign (INIT_EXPR, decl, result);
3150
3097
result = compound_expr (expr, return_expr (result));
3151
3098
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
+ }
3155
3105
3156
3106
return result;
3157
3107
}
0 commit comments