diff options
Diffstat (limited to 'gcc/cp/decl.c')
-rw-r--r-- | gcc/cp/decl.c | 119 |
1 files changed, 82 insertions, 37 deletions
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 95cf0f5..c746e33 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -5081,7 +5081,7 @@ end_cleanup_fn (void) /* Generate code to handle the destruction of DECL, an object with static storage duration. */ -void +tree register_dtor_fn (tree decl) { tree cleanup; @@ -5090,7 +5090,7 @@ register_dtor_fn (tree decl) tree fcall; if (TYPE_HAS_TRIVIAL_DESTRUCTOR (TREE_TYPE (decl))) - return; + return void_zero_node; /* Call build_cleanup before we enter the anonymous function so that any access checks will be done relative to the current scope, @@ -5129,7 +5129,7 @@ register_dtor_fn (tree decl) } else args = tree_cons (NULL_TREE, cleanup, NULL_TREE); - finish_expr_stmt (build_function_call (get_atexit_node (), args)); + return build_function_call (get_atexit_node (), args); } /* DECL is a VAR_DECL with static storage duration. INIT, if present, @@ -5151,36 +5151,42 @@ expand_static_init (tree decl, tree init) if (DECL_FUNCTION_SCOPE_P (decl)) { /* Emit code to perform this initialization but once. */ - tree if_stmt; - tree then_clause; - tree assignment; - tree guard; - tree guard_init; + tree if_stmt, inner_if_stmt; + tree then_clause, inner_then_clause; + tree guard, guard_addr, guard_addr_list; + tree acquire_fn, release_fn, abort_fn; + tree flag, begin; /* Emit code to perform this initialization but once. This code looks like: - static int guard = 0; - if (!guard) { - // Do initialization. - guard = 1; - // Register variable for destruction at end of program. + static <type> guard; + if (!guard.first_byte) { + if (__cxa_guard_acquire (&guard)) { + bool flag = false; + try { + // Do initialization. + flag = true; __cxa_guard_release (&guard); + // Register variable for destruction at end of program. + } catch { + if (!flag) __cxa_guard_abort (&guard); + } } - Note that the `temp' variable is only set to 1 *after* the + Note that the `flag' variable is only set to 1 *after* the initialization is complete. This ensures that an exception, thrown during the construction, will cause the variable to reinitialized when we pass through this code again, as per: [stmt.dcl] - If the initialization exits by throwing an exception, the + If the initialization exits by throwing an exception, the initialization is not complete, so it will be tried again the next time control enters the declaration. - In theory, this process should be thread-safe, too; multiple - threads should not be able to initialize the variable more - than once. We don't yet attempt to ensure thread-safety. */ + This process should be thread-safe, too; multiple threads + should not be able to initialize the variable more than + once. */ /* Create the guard variable. */ guard = get_guard (decl); @@ -5188,29 +5194,68 @@ expand_static_init (tree decl, tree init) /* Begin the conditional initialization. */ if_stmt = begin_if_stmt (); finish_if_stmt_cond (get_guard_cond (guard), if_stmt); - then_clause = begin_compound_stmt (0); - - /* Do the initialization itself. */ - assignment = init ? init : NULL_TREE; - - /* Once the assignment is complete, set TEMP to 1. Since the - construction of the static object is complete at this point, - we want to make sure TEMP is set to 1 even if a temporary - constructed during the initialization throws an exception - when it is destroyed. So, we combine the initialization and - the assignment to TEMP into a single expression, ensuring - that when we call finish_expr_stmt the cleanups will not be - run until after TEMP is set to 1. */ - guard_init = set_guard (guard); - if (assignment) - assignment = build_compound_expr (assignment, guard_init); + then_clause = begin_compound_stmt (BCS_NO_SCOPE); + + if (flag_threadsafe_statics) + { + guard_addr = build_address (guard); + guard_addr_list = build_tree_list (NULL_TREE, guard_addr); + + acquire_fn = get_identifier ("__cxa_guard_acquire"); + release_fn = get_identifier ("__cxa_guard_release"); + abort_fn = get_identifier ("__cxa_guard_abort"); + if (!get_global_value_if_present (acquire_fn, &acquire_fn)) + { + tree argtypes = tree_cons (NULL_TREE, TREE_TYPE (guard_addr), + void_list_node); + tree vfntype = build_function_type (void_type_node, argtypes); + acquire_fn = push_library_fn + (acquire_fn, build_function_type (integer_type_node, argtypes)); + release_fn = push_library_fn (release_fn, vfntype); + abort_fn = push_library_fn (abort_fn, vfntype); + } + else + { + release_fn = identifier_global_value (release_fn); + abort_fn = identifier_global_value (abort_fn); + } + + inner_if_stmt = begin_if_stmt (); + finish_if_stmt_cond (build_call (acquire_fn, guard_addr_list), + inner_if_stmt); + + inner_then_clause = begin_compound_stmt (BCS_NO_SCOPE); + begin = get_target_expr (boolean_false_node); + flag = TARGET_EXPR_SLOT (begin); + + TARGET_EXPR_CLEANUP (begin) + = build (COND_EXPR, void_type_node, flag, + void_zero_node, + build_call (abort_fn, guard_addr_list)); + CLEANUP_EH_ONLY (begin) = 1; + + /* Do the initialization itself. */ + init = add_stmt_to_compound (begin, init); + init = add_stmt_to_compound + (init, build (MODIFY_EXPR, void_type_node, flag, boolean_true_node)); + init = add_stmt_to_compound + (init, build_call (release_fn, guard_addr_list)); + } else - assignment = guard_init; - finish_expr_stmt (assignment); + init = add_stmt_to_compound (init, set_guard (guard)); /* Use atexit to register a function for destroying this static variable. */ - register_dtor_fn (decl); + init = add_stmt_to_compound (init, register_dtor_fn (decl)); + + finish_expr_stmt (init); + + if (flag_threadsafe_statics) + { + finish_compound_stmt (inner_then_clause); + finish_then_clause (inner_if_stmt); + finish_if_stmt (inner_if_stmt); + } finish_compound_stmt (then_clause); finish_then_clause (if_stmt); |