#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "tm.h"
#include "tree.h"
#include "cp-tree.h"
#include "c-common.h"
#include "tree-inline.h"
#include "tree-mudflap.h"
#include "except.h"
#include "toplev.h"
#include "flags.h"
#include "rtl.h"
#include "expr.h"
#include "output.h"
#include "timevar.h"
#include "debug.h"
#include "diagnostic.h"
#include "cgraph.h"
#include "tree-iterator.h"
#include "vec.h"
#include "target.h"
static tree maybe_convert_cond (tree);
static tree simplify_aggr_init_exprs_r (tree *, int *, void *);
static void emit_associated_thunks (tree);
static tree finalize_nrv_r (tree *, int *, void *);
typedef struct deferred_access GTY(())
{
VEC (deferred_access_check,gc)* GTY(()) deferred_access_checks;
enum deferring_kind deferring_access_checks_kind;
} deferred_access;
DEF_VEC_O (deferred_access);
DEF_VEC_ALLOC_O (deferred_access,gc);
static GTY(()) VEC(deferred_access,gc) *deferred_access_stack;
static GTY(()) unsigned deferred_access_no_check;
void
push_deferring_access_checks (deferring_kind deferring)
{
if (deferred_access_no_check || deferring == dk_no_check)
deferred_access_no_check++;
else
{
deferred_access *ptr;
ptr = VEC_safe_push (deferred_access, gc, deferred_access_stack, NULL);
ptr->deferred_access_checks = NULL;
ptr->deferring_access_checks_kind = deferring;
}
}
void
resume_deferring_access_checks (void)
{
if (!deferred_access_no_check)
VEC_last (deferred_access, deferred_access_stack)
->deferring_access_checks_kind = dk_deferred;
}
void
stop_deferring_access_checks (void)
{
if (!deferred_access_no_check)
VEC_last (deferred_access, deferred_access_stack)
->deferring_access_checks_kind = dk_no_deferred;
}
void
pop_deferring_access_checks (void)
{
if (deferred_access_no_check)
deferred_access_no_check--;
else
VEC_pop (deferred_access, deferred_access_stack);
}
VEC (deferred_access_check,gc)*
get_deferred_access_checks (void)
{
if (deferred_access_no_check)
return NULL;
else
return (VEC_last (deferred_access, deferred_access_stack)
->deferred_access_checks);
}
void
pop_to_parent_deferring_access_checks (void)
{
if (deferred_access_no_check)
deferred_access_no_check--;
else
{
VEC (deferred_access_check,gc) *checks;
deferred_access *ptr;
checks = (VEC_last (deferred_access, deferred_access_stack)
->deferred_access_checks);
VEC_pop (deferred_access, deferred_access_stack);
ptr = VEC_last (deferred_access, deferred_access_stack);
if (ptr->deferring_access_checks_kind == dk_no_deferred)
{
perform_access_checks (checks);
}
else
{
int i, j;
deferred_access_check *chk, *probe;
for (i = 0 ;
VEC_iterate (deferred_access_check, checks, i, chk) ;
++i)
{
for (j = 0 ;
VEC_iterate (deferred_access_check,
ptr->deferred_access_checks, j, probe) ;
++j)
{
if (probe->binfo == chk->binfo &&
probe->decl == chk->decl &&
probe->diag_decl == chk->diag_decl)
goto found;
}
VEC_safe_push (deferred_access_check, gc,
ptr->deferred_access_checks, chk);
found:;
}
}
}
}
void
perform_access_checks (VEC (deferred_access_check,gc)* checks)
{
int i;
deferred_access_check *chk;
if (!checks)
return;
for (i = 0 ; VEC_iterate (deferred_access_check, checks, i, chk) ; ++i)
enforce_access (chk->binfo, chk->decl, chk->diag_decl);
}
void
perform_deferred_access_checks (void)
{
perform_access_checks (get_deferred_access_checks ());
}
void
perform_or_defer_access_check (tree binfo, tree decl, tree diag_decl)
{
int i;
deferred_access *ptr;
deferred_access_check *chk;
deferred_access_check *new_access;
if (deferred_access_no_check)
return;
gcc_assert (TREE_CODE (binfo) == TREE_BINFO);
ptr = VEC_last (deferred_access, deferred_access_stack);
if (ptr->deferring_access_checks_kind == dk_no_deferred)
{
enforce_access (binfo, decl, diag_decl);
return;
}
for (i = 0 ;
VEC_iterate (deferred_access_check,
ptr->deferred_access_checks, i, chk) ;
++i)
{
if (chk->decl == decl && chk->binfo == binfo &&
chk->diag_decl == diag_decl)
{
return;
}
}
new_access =
VEC_safe_push (deferred_access_check, gc,
ptr->deferred_access_checks, 0);
new_access->binfo = binfo;
new_access->decl = decl;
new_access->diag_decl = diag_decl;
}
int
stmts_are_full_exprs_p (void)
{
return current_stmt_tree ()->stmts_are_full_exprs_p;
}
tree
add_stmt (tree t)
{
enum tree_code code = TREE_CODE (t);
if (EXPR_P (t) && code != LABEL_EXPR)
{
if (!EXPR_HAS_LOCATION (t))
SET_EXPR_LOCATION (t, input_location);
STMT_IS_FULL_EXPR_P (t) = stmts_are_full_exprs_p ();
}
append_to_statement_list_force (t, &cur_stmt_list);
return t;
}
stmt_tree
current_stmt_tree (void)
{
return (cfun
? &cfun->language->base.x_stmt_tree
: &scope_chain->x_stmt_tree);
}
static tree
maybe_cleanup_point_expr (tree expr)
{
if (!processing_template_decl && stmts_are_full_exprs_p ())
expr = fold_build_cleanup_point_expr (TREE_TYPE (expr), expr);
return expr;
}
static tree
maybe_cleanup_point_expr_void (tree expr)
{
if (!processing_template_decl && stmts_are_full_exprs_p ())
expr = fold_build_cleanup_point_expr (void_type_node, expr);
return expr;
}
void
add_decl_expr (tree decl)
{
tree r = build_stmt (DECL_EXPR, decl);
if (DECL_INITIAL (decl)
|| (DECL_SIZE (decl) && TREE_SIDE_EFFECTS (DECL_SIZE (decl))))
r = maybe_cleanup_point_expr_void (r);
add_stmt (r);
}
int
anon_aggr_type_p (tree node)
{
return ANON_AGGR_TYPE_P (node);
}
tree
do_poplevel (tree stmt_list)
{
tree block = NULL;
if (stmts_are_full_exprs_p ())
block = poplevel (kept_level_p (), 1, 0);
stmt_list = pop_stmt_list (stmt_list);
if (!processing_template_decl)
{
stmt_list = c_build_bind_expr (block, stmt_list);
}
return stmt_list;
}
static tree
do_pushlevel (scope_kind sk)
{
tree ret = push_stmt_list ();
if (stmts_are_full_exprs_p ())
begin_scope (sk, NULL);
return ret;
}
void
push_cleanup (tree decl, tree cleanup, bool eh_only)
{
tree stmt = build_stmt (CLEANUP_STMT, NULL, cleanup, decl);
CLEANUP_EH_ONLY (stmt) = eh_only;
add_stmt (stmt);
CLEANUP_BODY (stmt) = push_stmt_list ();
}
static void
begin_cond (tree *cond_p)
{
if (processing_template_decl)
*cond_p = push_stmt_list ();
}
static void
finish_cond (tree *cond_p, tree expr)
{
if (processing_template_decl)
{
tree cond = pop_stmt_list (*cond_p);
if (TREE_CODE (cond) == DECL_EXPR)
expr = cond;
}
*cond_p = expr;
}
static void
simplify_loop_decl_cond (tree *cond_p, tree body)
{
tree cond, if_stmt;
if (!TREE_SIDE_EFFECTS (body))
return;
cond = *cond_p;
*cond_p = boolean_true_node;
if_stmt = begin_if_stmt ();
cond = build_unary_op (TRUTH_NOT_EXPR, cond, 0);
finish_if_stmt_cond (cond, if_stmt);
finish_break_stmt ();
finish_then_clause (if_stmt);
finish_if_stmt (if_stmt);
}
tree
finish_goto_stmt (tree destination)
{
if (TREE_CODE (destination) == IDENTIFIER_NODE)
destination = lookup_label (destination);
if (TREE_CODE (destination) == LABEL_DECL)
TREE_USED (destination) = 1;
else
{
if (!processing_template_decl)
destination = decay_conversion (destination);
DECL_UNINLINABLE (current_function_decl) = 1;
}
check_goto (destination);
return add_stmt (build_stmt (GOTO_EXPR, destination));
}
static tree
maybe_convert_cond (tree cond)
{
if (!cond)
return NULL_TREE;
if (processing_template_decl)
return cond;
cond = convert_from_reference (cond);
return condition_conversion (cond);
}
tree
finish_expr_stmt (tree expr)
{
tree r = NULL_TREE;
if (expr != NULL_TREE)
{
if (!processing_template_decl)
{
if (warn_sequence_point)
verify_sequence_points (expr);
expr = convert_to_void (expr, "statement");
}
else if (!type_dependent_expression_p (expr))
convert_to_void (build_non_dependent_expr (expr), "statement");
if (TREE_CODE (expr) != CLEANUP_POINT_EXPR)
{
if (TREE_CODE (expr) != EXPR_STMT)
expr = build_stmt (EXPR_STMT, expr);
expr = maybe_cleanup_point_expr_void (expr);
}
r = add_stmt (expr);
}
finish_stmt ();
return r;
}
tree
begin_if_stmt (void)
{
tree r, scope;
scope = do_pushlevel (sk_block);
r = build_stmt (IF_STMT, NULL_TREE, NULL_TREE, NULL_TREE);
TREE_CHAIN (r) = scope;
begin_cond (&IF_COND (r));
return r;
}
void
finish_if_stmt_cond (tree cond, tree if_stmt)
{
finish_cond (&IF_COND (if_stmt), maybe_convert_cond (cond));
add_stmt (if_stmt);
THEN_CLAUSE (if_stmt) = push_stmt_list ();
}
tree
finish_then_clause (tree if_stmt)
{
THEN_CLAUSE (if_stmt) = pop_stmt_list (THEN_CLAUSE (if_stmt));
return if_stmt;
}
void
begin_else_clause (tree if_stmt)
{
ELSE_CLAUSE (if_stmt) = push_stmt_list ();
}
void
finish_else_clause (tree if_stmt)
{
ELSE_CLAUSE (if_stmt) = pop_stmt_list (ELSE_CLAUSE (if_stmt));
}
void
finish_if_stmt (tree if_stmt)
{
tree scope = TREE_CHAIN (if_stmt);
TREE_CHAIN (if_stmt) = NULL;
add_stmt (do_poplevel (scope));
finish_stmt ();
empty_body_warning (THEN_CLAUSE (if_stmt), ELSE_CLAUSE (if_stmt));
}
tree
\
begin_while_stmt (tree attribs)
\
{
tree r;
\
r = build_stmt (WHILE_STMT, NULL_TREE, NULL_TREE, attribs);
\
add_stmt (r);
WHILE_BODY (r) = do_pushlevel (sk_block);
begin_cond (&WHILE_COND (r));
return r;
}
void
finish_while_stmt_cond (tree cond, tree while_stmt)
{
finish_cond (&WHILE_COND (while_stmt), maybe_convert_cond (cond));
simplify_loop_decl_cond (&WHILE_COND (while_stmt), WHILE_BODY (while_stmt));
}
void
finish_while_stmt (tree while_stmt)
{
WHILE_BODY (while_stmt) = do_poplevel (WHILE_BODY (while_stmt));
finish_stmt ();
}
tree
\
begin_do_stmt (tree attribs)
\
{
\
tree r = build_stmt (DO_STMT, NULL_TREE, NULL_TREE, attribs, NULL_TREE);
\
add_stmt (r);
DO_BODY (r) = push_stmt_list ();
return r;
}
void
finish_do_body (tree do_stmt)
{
DO_BODY (do_stmt) = pop_stmt_list (DO_BODY (do_stmt));
}
void
finish_do_stmt (tree cond, tree do_stmt)
{
cond = maybe_convert_cond (cond);
DO_COND (do_stmt) = cond;
finish_stmt ();
}
tree
finish_return_stmt (tree expr)
{
tree r;
bool no_warning;
expr = check_return_expr (expr, &no_warning);
if (flag_openmp && !check_omp_return ())
return error_mark_node;
if (!processing_template_decl)
{
if (DECL_DESTRUCTOR_P (current_function_decl)
|| (DECL_CONSTRUCTOR_P (current_function_decl)
&& targetm.cxx.cdtor_returns_this ()))
{
return finish_goto_stmt (cdtor_label);
}
}
r = build_stmt (RETURN_EXPR, expr);
TREE_NO_WARNING (r) |= no_warning;
r = maybe_cleanup_point_expr_void (r);
r = add_stmt (r);
finish_stmt ();
return r;
}
tree
\
begin_for_stmt (tree attribs)
\
{
tree r;
r = build_stmt (FOR_STMT, NULL_TREE, NULL_TREE,
\
NULL_TREE, NULL_TREE, attribs);
\
if (flag_new_for_scope > 0)
TREE_CHAIN (r) = do_pushlevel (sk_for);
if (processing_template_decl)
FOR_INIT_STMT (r) = push_stmt_list ();
return r;
}
void
finish_for_init_stmt (tree for_stmt)
{
if (processing_template_decl)
FOR_INIT_STMT (for_stmt) = pop_stmt_list (FOR_INIT_STMT (for_stmt));
add_stmt (for_stmt);
FOR_BODY (for_stmt) = do_pushlevel (sk_block);
begin_cond (&FOR_COND (for_stmt));
}
void
finish_for_cond (tree cond, tree for_stmt)
{
finish_cond (&FOR_COND (for_stmt), maybe_convert_cond (cond));
simplify_loop_decl_cond (&FOR_COND (for_stmt), FOR_BODY (for_stmt));
}
void
finish_for_expr (tree expr, tree for_stmt)
{
if (!expr)
return;
if (type_unknown_p (expr))
{
cxx_incomplete_type_error (expr, TREE_TYPE (expr));
expr = error_mark_node;
}
if (!processing_template_decl)
{
if (warn_sequence_point)
verify_sequence_points (expr);
expr = convert_to_void (expr, "3rd expression in for");
}
else if (!type_dependent_expression_p (expr))
convert_to_void (build_non_dependent_expr (expr), "3rd expression in for");
expr = maybe_cleanup_point_expr_void (expr);
FOR_EXPR (for_stmt) = expr;
}
void
finish_for_stmt (tree for_stmt)
{
FOR_BODY (for_stmt) = do_poplevel (FOR_BODY (for_stmt));
if (flag_new_for_scope > 0)
{
tree scope = TREE_CHAIN (for_stmt);
TREE_CHAIN (for_stmt) = NULL;
add_stmt (do_poplevel (scope));
}
finish_stmt ();
}
tree
finish_break_stmt (void)
{
return add_stmt (build_stmt (BREAK_STMT));
}
tree
finish_continue_stmt (void)
{
return add_stmt (build_stmt (CONTINUE_STMT));
}
tree
begin_switch_stmt (void)
{
tree r, scope;
r = build_stmt (SWITCH_STMT, NULL_TREE, NULL_TREE, NULL_TREE);
scope = do_pushlevel (sk_block);
TREE_CHAIN (r) = scope;
begin_cond (&SWITCH_STMT_COND (r));
return r;
}
void
finish_switch_cond (tree cond, tree switch_stmt)
{
tree orig_type = NULL;
if (!processing_template_decl)
{
tree index;
cond = build_expr_type_conversion (WANT_INT | WANT_ENUM, cond, true);
if (cond == NULL_TREE)
{
error ("switch quantity not an integer");
cond = error_mark_node;
}
orig_type = TREE_TYPE (cond);
if (cond != error_mark_node)
{
cond = perform_integral_promotions (cond);
cond = maybe_cleanup_point_expr (cond);
}
if (cond != error_mark_node)
{
index = get_unwidened (cond, NULL_TREE);
if (TYPE_UNSIGNED (TREE_TYPE (cond))
== TYPE_UNSIGNED (TREE_TYPE (index)))
cond = index;
}
}
finish_cond (&SWITCH_STMT_COND (switch_stmt), cond);
SWITCH_STMT_TYPE (switch_stmt) = orig_type;
add_stmt (switch_stmt);
push_switch (switch_stmt);
SWITCH_STMT_BODY (switch_stmt) = push_stmt_list ();
}
void
finish_switch_stmt (tree switch_stmt)
{
tree scope;
SWITCH_STMT_BODY (switch_stmt) =
pop_stmt_list (SWITCH_STMT_BODY (switch_stmt));
pop_switch ();
finish_stmt ();
scope = TREE_CHAIN (switch_stmt);
TREE_CHAIN (switch_stmt) = NULL;
add_stmt (do_poplevel (scope));
}
tree
begin_try_block (void)
{
tree r = build_stmt (TRY_BLOCK, NULL_TREE, NULL_TREE);
add_stmt (r);
TRY_STMTS (r) = push_stmt_list ();
return r;
}
tree
begin_function_try_block (tree *compound_stmt)
{
tree r;
*compound_stmt = begin_compound_stmt (0);
r = begin_try_block ();
FN_TRY_BLOCK_P (r) = 1;
return r;
}
void
finish_try_block (tree try_block)
{
TRY_STMTS (try_block) = pop_stmt_list (TRY_STMTS (try_block));
TRY_HANDLERS (try_block) = push_stmt_list ();
}
void
finish_cleanup_try_block (tree try_block)
{
TRY_STMTS (try_block) = pop_stmt_list (TRY_STMTS (try_block));
}
void
finish_cleanup (tree cleanup, tree try_block)
{
TRY_HANDLERS (try_block) = cleanup;
CLEANUP_P (try_block) = 1;
}
void
finish_function_try_block (tree try_block)
{
finish_try_block (try_block);
in_function_try_handler = 1;
}
void
finish_handler_sequence (tree try_block)
{
TRY_HANDLERS (try_block) = pop_stmt_list (TRY_HANDLERS (try_block));
check_handlers (TRY_HANDLERS (try_block));
}
void
finish_function_handler_sequence (tree try_block, tree compound_stmt)
{
in_function_try_handler = 0;
finish_handler_sequence (try_block);
finish_compound_stmt (compound_stmt);
}
tree
begin_handler (void)
{
tree r;
r = build_stmt (HANDLER, NULL_TREE, NULL_TREE);
add_stmt (r);
HANDLER_BODY (r) = do_pushlevel (sk_catch);
return r;
}
void
finish_handler_parms (tree decl, tree handler)
{
tree type = NULL_TREE;
if (processing_template_decl)
{
if (decl)
{
decl = pushdecl (decl);
decl = push_template_decl (decl);
HANDLER_PARMS (handler) = decl;
type = TREE_TYPE (decl);
}
}
else
type = expand_start_catch_block (decl);
HANDLER_TYPE (handler) = type;
if (!processing_template_decl && type)
mark_used (eh_type_info (type));
}
void
finish_handler (tree handler)
{
if (!processing_template_decl)
expand_end_catch_block ();
HANDLER_BODY (handler) = do_poplevel (HANDLER_BODY (handler));
}
tree
begin_compound_stmt (unsigned int flags)
{
tree r;
if (flags & BCS_NO_SCOPE)
{
r = push_stmt_list ();
STATEMENT_LIST_NO_SCOPE (r) = 1;
keep_next_level (false);
}
else
r = do_pushlevel (flags & BCS_TRY_BLOCK ? sk_try : sk_block);
if (processing_template_decl)
{
r = build3 (BIND_EXPR, NULL, NULL, r, NULL);
BIND_EXPR_TRY_BLOCK (r) = (flags & BCS_TRY_BLOCK) != 0;
BIND_EXPR_BODY_BLOCK (r) = (flags & BCS_FN_BODY) != 0;
TREE_SIDE_EFFECTS (r) = 1;
}
return r;
}
void
finish_compound_stmt (tree stmt)
{
if (TREE_CODE (stmt) == BIND_EXPR)
BIND_EXPR_BODY (stmt) = do_poplevel (BIND_EXPR_BODY (stmt));
else if (STATEMENT_LIST_NO_SCOPE (stmt))
stmt = pop_stmt_list (stmt);
else
{
objc_clear_super_receiver ();
stmt = do_poplevel (stmt);
}
add_stmt (stmt);
finish_stmt ();
}
tree
finish_asm_stmt (int volatile_p, tree string, tree output_operands,
tree input_operands, tree clobbers, tree uses)
{
tree r;
tree t;
int ninputs = list_length (input_operands);
int noutputs = list_length (output_operands);
if (!processing_template_decl)
{
const char *constraint;
const char **oconstraints;
bool allows_mem, allows_reg, is_inout;
tree operand;
int i;
oconstraints = (const char **) alloca (noutputs * sizeof (char *));
string = resolve_asm_operand_names (string, output_operands,
input_operands);
for (i = 0, t = output_operands; t; t = TREE_CHAIN (t), ++i)
{
operand = TREE_VALUE (t);
STRIP_NOPS (operand);
if (!lvalue_or_else (&operand, lv_asm))
operand = error_mark_node;
if (operand != error_mark_node
&& (TREE_READONLY (operand)
|| CP_TYPE_CONST_P (TREE_TYPE (operand))
|| TREE_CODE (TREE_TYPE (operand)) == FUNCTION_TYPE
|| TREE_CODE (TREE_TYPE (operand)) == METHOD_TYPE
|| (CLASS_TYPE_P (TREE_TYPE (operand))
&& C_TYPE_FIELDS_READONLY (TREE_TYPE (operand)))))
readonly_error (operand, "assignment (via 'asm' output)", 0);
constraint = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (t)));
oconstraints[i] = constraint;
if (parse_output_constraint (&constraint, i, ninputs, noutputs,
&allows_mem, &allows_reg, &is_inout))
{
if (!allows_reg && !cxx_mark_addressable (operand))
operand = error_mark_node;
}
else
operand = error_mark_node;
TREE_VALUE (t) = operand;
}
for (i = 0, t = input_operands; t; ++i, t = TREE_CHAIN (t))
{
constraint = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (t)));
operand = decay_conversion (TREE_VALUE (t));
if (TREE_TYPE (operand) == unknown_type_node)
{
error ("type of asm operand %qE could not be determined",
TREE_VALUE (t));
operand = error_mark_node;
}
if (parse_input_constraint (&constraint, i, ninputs, noutputs, 0,
oconstraints, &allows_mem, &allows_reg))
{
if (!allows_reg && allows_mem)
{
STRIP_NOPS (operand);
if (!cxx_mark_addressable (operand))
operand = error_mark_node;
}
}
else
operand = error_mark_node;
TREE_VALUE (t) = operand;
}
}
r = build_stmt (ASM_EXPR, string,
output_operands, input_operands,
clobbers, uses);
ASM_VOLATILE_P (r) = volatile_p || noutputs == 0;
r = maybe_cleanup_point_expr_void (r);
return add_stmt (r);
}
tree
finish_label_stmt (tree name)
{
tree decl = define_label (input_location, name);
if (decl == error_mark_node)
return error_mark_node;
return add_stmt (build_stmt (LABEL_EXPR, decl));
}
void
finish_label_decl (tree name)
{
tree decl = declare_local_label (name);
add_decl_expr (decl);
}
void
finish_decl_cleanup (tree decl, tree cleanup)
{
push_cleanup (decl, cleanup, false);
}
void
finish_eh_cleanup (tree cleanup)
{
push_cleanup (NULL, cleanup, true);
}
void
finish_mem_initializers (tree mem_inits)
{
mem_inits = nreverse (mem_inits);
if (processing_template_decl)
add_stmt (build_min_nt (CTOR_INITIALIZER, mem_inits));
else
emit_mem_initializers (mem_inits);
}
tree
finish_parenthesized_expr (tree expr)
{
if (EXPR_P (expr))
TREE_NO_WARNING (expr) = 1;
if (TREE_CODE (expr) == OFFSET_REF)
PTRMEM_OK_P (expr) = 0;
if (TREE_CODE (expr) == STRING_CST)
PAREN_STRING_LITERAL_P (expr) = 1;
return expr;
}
tree
finish_non_static_data_member (tree decl, tree object, tree qualifying_scope)
{
gcc_assert (TREE_CODE (decl) == FIELD_DECL);
if (!object)
{
if (current_function_decl
&& DECL_STATIC_FUNCTION_P (current_function_decl))
error ("invalid use of member %q+D in static member function", decl);
else
error ("invalid use of non-static data member %q+D", decl);
error ("from this location");
return error_mark_node;
}
TREE_USED (current_class_ptr) = 1;
if (processing_template_decl && !qualifying_scope)
{
tree type = TREE_TYPE (decl);
if (TREE_CODE (type) == REFERENCE_TYPE)
type = TREE_TYPE (type);
else
{
int quals = cp_type_quals (TREE_TYPE (current_class_ref));
if (DECL_MUTABLE_P (decl))
quals &= ~TYPE_QUAL_CONST;
quals |= cp_type_quals (TREE_TYPE (decl));
type = cp_build_qualified_type (type, quals);
}
return build_min (COMPONENT_REF, type, object, decl, NULL_TREE);
}
else
{
tree access_type = TREE_TYPE (object);
tree lookup_context = context_for_name_lookup (decl);
while (!DERIVED_FROM_P (lookup_context, access_type))
{
access_type = TYPE_CONTEXT (access_type);
while (access_type && DECL_P (access_type))
access_type = DECL_CONTEXT (access_type);
if (!access_type)
{
error ("object missing in reference to %q+D", decl);
error ("from this location");
return error_mark_node;
}
}
if (processing_template_decl)
return build_qualified_name (TREE_TYPE (decl),
qualifying_scope,
DECL_NAME (decl),
false);
perform_or_defer_access_check (TYPE_BINFO (access_type), decl,
decl);
if (qualifying_scope)
{
tree binfo = NULL_TREE;
object = build_scoped_ref (object, qualifying_scope,
&binfo);
}
return build_class_member_access_expr (object, decl,
NULL_TREE,
false);
}
}
void
check_accessibility_of_qualified_id (tree decl,
tree object_type,
tree nested_name_specifier)
{
tree scope;
tree qualifying_type = NULL_TREE;
if (deferred_access_no_check)
return;
scope = context_for_name_lookup (decl);
if (!TYPE_P (scope))
return;
if (object_type
&& CLASS_TYPE_P (object_type)
&& DERIVED_FROM_P (scope, object_type))
qualifying_type = object_type;
else if (nested_name_specifier)
{
if (DECL_NONSTATIC_MEMBER_P (decl)
&& current_class_ptr
&& DERIVED_FROM_P (scope, current_class_type))
qualifying_type = current_class_type;
else
qualifying_type = nested_name_specifier;
}
else
qualifying_type = currently_open_derived_class (scope);
if (qualifying_type
&& CLASS_TYPE_P (qualifying_type)
&& !dependent_type_p (qualifying_type))
perform_or_defer_access_check (TYPE_BINFO (qualifying_type), decl,
decl);
}
tree
finish_qualified_id_expr (tree qualifying_class,
tree expr,
bool done,
bool address_p,
bool template_p,
bool template_arg_p)
{
gcc_assert (TYPE_P (qualifying_class));
if (error_operand_p (expr))
return error_mark_node;
if (DECL_P (expr) || BASELINK_P (expr))
mark_used (expr);
if (template_p)
check_template_keyword (expr);
if (address_p && done)
{
if (TREE_CODE (expr) == SCOPE_REF)
expr = TREE_OPERAND (expr, 1);
expr = build_offset_ref (qualifying_class, expr,
true);
return expr;
}
if (template_arg_p)
;
else if (TREE_CODE (expr) == FIELD_DECL)
expr = finish_non_static_data_member (expr, current_class_ref,
qualifying_class);
else if (BASELINK_P (expr) && !processing_template_decl)
{
tree fns;
fns = BASELINK_FUNCTIONS (expr);
if (TREE_CODE (fns) == TEMPLATE_ID_EXPR)
fns = TREE_OPERAND (fns, 0);
if (!shared_member_p (fns)
&& current_class_type
&& DERIVED_FROM_P (qualifying_class, current_class_type))
expr = (build_class_member_access_expr
(maybe_dummy_object (qualifying_class, NULL),
expr,
BASELINK_ACCESS_BINFO (expr),
false));
else if (done)
expr = build_offset_ref (qualifying_class, expr, false);
}
return expr;
}
tree
begin_stmt_expr (void)
{
return push_stmt_list ();
}
tree
finish_stmt_expr_expr (tree expr, tree stmt_expr)
{
if (error_operand_p (expr))
return error_mark_node;
if (expr)
{
tree type = TREE_TYPE (expr);
if (processing_template_decl)
{
expr = build_stmt (EXPR_STMT, expr);
expr = add_stmt (expr);
EXPR_STMT_STMT_EXPR_RESULT (expr) = 1;
}
else if (VOID_TYPE_P (type))
{
expr = finish_expr_stmt (expr);
}
else
{
expr = force_rvalue (expr);
if (error_operand_p (expr))
return error_mark_node;
type = TREE_TYPE (expr);
if (TREE_CODE (expr) != CLEANUP_POINT_EXPR)
expr = maybe_cleanup_point_expr (expr);
add_stmt (expr);
}
TREE_TYPE (stmt_expr) = type;
}
return stmt_expr;
}
tree
finish_stmt_expr (tree stmt_expr, bool has_no_scope)
{
tree type;
tree result;
if (error_operand_p (stmt_expr))
return error_mark_node;
gcc_assert (TREE_CODE (stmt_expr) == STATEMENT_LIST);
type = TREE_TYPE (stmt_expr);
result = pop_stmt_list (stmt_expr);
TREE_TYPE (result) = type;
if (processing_template_decl)
{
result = build_min (STMT_EXPR, type, result);
TREE_SIDE_EFFECTS (result) = 1;
STMT_EXPR_NO_SCOPE (result) = has_no_scope;
}
else if (CLASS_TYPE_P (type))
{
result = force_target_expr (type, result);
}
return result;
}
tree
perform_koenig_lookup (tree fn, tree args)
{
tree identifier = NULL_TREE;
tree functions = NULL_TREE;
if (TREE_CODE (fn) == IDENTIFIER_NODE)
identifier = fn;
else if (is_overloaded_fn (fn))
{
functions = fn;
identifier = DECL_NAME (get_first_fn (functions));
}
else if (DECL_P (fn))
{
functions = fn;
identifier = DECL_NAME (fn);
}
if (!any_type_dependent_arguments_p (args))
{
fn = lookup_arg_dependent (identifier, functions, args);
if (!fn)
fn = unqualified_fn_lookup_error (identifier);
}
return fn;
}
tree
finish_call_expr (tree fn, tree args, bool disallow_virtual, bool koenig_p)
{
tree result;
tree orig_fn;
tree orig_args;
if (fn == error_mark_node || args == error_mark_node)
return error_mark_node;
gcc_assert (!args || TREE_CODE (args) == TREE_LIST);
gcc_assert (!TYPE_P (fn));
orig_fn = fn;
orig_args = args;
if (processing_template_decl)
{
if (type_dependent_expression_p (fn)
|| any_type_dependent_arguments_p (args))
{
result = build_nt (CALL_EXPR, fn, args, NULL_TREE);
KOENIG_LOOKUP_P (result) = koenig_p;
return result;
}
if (!BASELINK_P (fn)
&& TREE_CODE (fn) != PSEUDO_DTOR_EXPR
&& TREE_TYPE (fn) != unknown_type_node)
fn = build_non_dependent_expr (fn);
args = build_non_dependent_args (orig_args);
}
if (is_overloaded_fn (fn))
fn = baselink_for_fns (fn);
result = NULL_TREE;
if (BASELINK_P (fn))
{
tree object;
if (current_class_type
&& DERIVED_FROM_P (BINFO_TYPE (BASELINK_ACCESS_BINFO (fn)),
current_class_type)
&& current_class_ref)
object = maybe_dummy_object (BINFO_TYPE (BASELINK_ACCESS_BINFO (fn)),
NULL);
else
{
tree representative_fn;
representative_fn = BASELINK_FUNCTIONS (fn);
if (TREE_CODE (representative_fn) == TEMPLATE_ID_EXPR)
representative_fn = TREE_OPERAND (representative_fn, 0);
representative_fn = get_first_fn (representative_fn);
object = build_dummy_object (DECL_CONTEXT (representative_fn));
}
if (processing_template_decl)
{
if (type_dependent_expression_p (object))
return build_nt (CALL_EXPR, orig_fn, orig_args, NULL_TREE);
object = build_non_dependent_expr (object);
}
result = build_new_method_call (object, fn, args, NULL_TREE,
(disallow_virtual
? LOOKUP_NONVIRTUAL : 0),
NULL);
}
else if (is_overloaded_fn (fn))
{
if (TREE_CODE (fn) == FUNCTION_DECL
&& (DECL_BUILT_IN_CLASS (fn) == BUILT_IN_NORMAL
|| DECL_BUILT_IN_CLASS (fn) == BUILT_IN_MD))
result = resolve_overloaded_builtin (fn, args);
if (!result)
result = build_new_function_call (fn, args, koenig_p);
}
else if (TREE_CODE (fn) == PSEUDO_DTOR_EXPR)
{
if (args)
error ("arguments to destructor are not allowed");
result = build1 (NOP_EXPR,
void_type_node,
TREE_OPERAND (fn, 0));
TREE_SIDE_EFFECTS (result) = 1;
}
else if (CLASS_TYPE_P (TREE_TYPE (fn)))
result = build_new_op (CALL_EXPR, LOOKUP_NORMAL, fn, args, NULL_TREE,
NULL);
if (!result)
result = build_function_call (fn, args);
if (processing_template_decl)
{
result = build3 (CALL_EXPR, TREE_TYPE (result), orig_fn,
orig_args, NULL_TREE);
KOENIG_LOOKUP_P (result) = koenig_p;
}
return result;
}
tree
finish_increment_expr (tree expr, enum tree_code code)
{
return build_x_unary_op (code, expr);
}
tree
finish_this_expr (void)
{
tree result;
if (current_class_ptr)
{
result = current_class_ptr;
}
else if (current_function_decl
&& DECL_STATIC_FUNCTION_P (current_function_decl))
{
error ("%<this%> is unavailable for static member functions");
result = error_mark_node;
}
else
{
if (current_function_decl)
error ("invalid use of %<this%> in non-member function");
else
error ("invalid use of %<this%> at top level");
result = error_mark_node;
}
return result;
}
tree
finish_pseudo_destructor_expr (tree object, tree scope, tree destructor)
{
if (destructor == error_mark_node)
return error_mark_node;
gcc_assert (TYPE_P (destructor));
if (!processing_template_decl)
{
if (scope == error_mark_node)
{
error ("invalid qualifying scope in pseudo-destructor name");
return error_mark_node;
}
if (scope && TYPE_P (scope) && !check_dtor_name (scope, destructor))
{
error ("qualified type %qT does not match destructor name ~%qT",
scope, destructor);
return error_mark_node;
}
if (!same_type_ignoring_top_level_qualifiers_p (TREE_TYPE (object),
destructor))
{
error ("%qE is not of type %qT", object, destructor);
return error_mark_node;
}
}
return build3 (PSEUDO_DTOR_EXPR, void_type_node, object, scope, destructor);
}
tree
finish_unary_op_expr (enum tree_code code, tree expr)
{
tree result = build_x_unary_op (code, expr);
if (code == NEGATE_EXPR && TREE_CODE (expr) == INTEGER_CST
&& TREE_CODE (result) == INTEGER_CST
&& !TYPE_UNSIGNED (TREE_TYPE (result))
&& INT_CST_LT (result, integer_zero_node))
{
result = copy_node (result);
TREE_NEGATED_INT (result) = 1;
}
overflow_warning (result);
return result;
}
tree
finish_compound_literal (tree type, VEC(constructor_elt,gc) *initializer_list)
{
tree var;
tree compound_literal;
if (!TYPE_OBJ_P (type))
{
error ("compound literal of non-object type %qT", type);
return error_mark_node;
}
compound_literal = build_constructor (NULL_TREE, initializer_list);
if (processing_template_decl)
{
TREE_TYPE (compound_literal) = type;
TREE_HAS_CONSTRUCTOR (compound_literal) = 1;
return compound_literal;
}
var = create_temporary_var (type);
if (!current_function_decl)
{
TREE_STATIC (var) = 1;
TREE_PUBLIC (var) = 0;
DECL_NAME (var) = make_anon_name ();
}
pushdecl (var);
cp_finish_decl (var, compound_literal,
false,
NULL_TREE,
LOOKUP_ONLYCONVERTING);
return var;
}
tree
finish_fname (tree id)
{
tree decl;
decl = fname_decl (C_RID_CODE (id), id);
if (processing_template_decl)
decl = DECL_NAME (decl);
return decl;
}
void
finish_translation_unit (void)
{
pop_everything ();
while (current_namespace != global_namespace)
pop_namespace ();
finish_fname_decls ();
}
tree
finish_template_type_parm (tree aggr, tree identifier)
{
if (aggr != class_type_node)
{
pedwarn ("template type parameters must use the keyword %<class%> or %<typename%>");
aggr = class_type_node;
}
return build_tree_list (aggr, identifier);
}
tree
finish_template_template_parm (tree aggr, tree identifier)
{
tree decl = build_decl (TYPE_DECL, identifier, NULL_TREE);
tree tmpl = build_lang_decl (TEMPLATE_DECL, identifier, NULL_TREE);
DECL_TEMPLATE_PARMS (tmpl) = current_template_parms;
DECL_TEMPLATE_RESULT (tmpl) = decl;
DECL_ARTIFICIAL (decl) = 1;
end_template_decl ();
gcc_assert (DECL_TEMPLATE_PARMS (tmpl));
return finish_template_type_parm (aggr, tmpl);
}
tree
check_template_template_default_arg (tree argument)
{
if (TREE_CODE (argument) != TEMPLATE_DECL
&& TREE_CODE (argument) != TEMPLATE_TEMPLATE_PARM
&& TREE_CODE (argument) != UNBOUND_CLASS_TEMPLATE)
{
if (TREE_CODE (argument) == TYPE_DECL)
error ("invalid use of type %qT as a default value for a template "
"template-parameter", TREE_TYPE (argument));
else
error ("invalid default argument for a template template parameter");
return error_mark_node;
}
return argument;
}
tree
begin_class_definition (tree t, tree attributes)
{
if (t == error_mark_node)
return error_mark_node;
if (processing_template_parmlist)
{
error ("definition of %q#T inside template parameter list", t);
return error_mark_node;
}
else if (TREE_CODE (t) == TYPENAME_TYPE)
{
error ("invalid definition of qualified type %qT", t);
t = error_mark_node;
}
if (t == error_mark_node || ! IS_AGGR_TYPE (t))
{
t = make_aggr_type (RECORD_TYPE);
pushtag (make_anon_name (), t, ts_current);
}
DECL_SOURCE_LOCATION (TYPE_NAME (t)) = input_location;
if (TYPE_BEING_DEFINED (t))
{
t = make_aggr_type (TREE_CODE (t));
pushtag (TYPE_IDENTIFIER (t), t, ts_current);
}
maybe_process_partial_specialization (t);
pushclass (t);
TYPE_BEING_DEFINED (t) = 1;
cplus_decl_attributes (&t, attributes, (int) ATTR_FLAG_TYPE_IN_PLACE);
if (flag_pack_struct)
{
tree v;
TYPE_PACKED (t) = 1;
for (v = TYPE_NEXT_VARIANT (t); v; v = TYPE_NEXT_VARIANT (v))
TYPE_PACKED (v) = 1;
}
if (! TYPE_ANONYMOUS_P (t))
{
struct c_fileinfo *finfo = get_fileinfo (input_filename);
CLASSTYPE_INTERFACE_ONLY (t) = finfo->interface_only;
SET_CLASSTYPE_INTERFACE_UNKNOWN_X
(t, finfo->interface_unknown);
}
reset_specialization();
build_self_reference ();
return t;
}
void
finish_member_declaration (tree decl)
{
if (decl == error_mark_node || decl == NULL_TREE)
return;
if (decl == void_type_node)
return;
gcc_assert (TREE_CHAIN (decl) == NULL_TREE);
TREE_PRIVATE (decl)
= (current_access_specifier == access_private_node);
TREE_PROTECTED (decl)
= (current_access_specifier == access_protected_node);
if (TREE_CODE (decl) == TEMPLATE_DECL)
{
TREE_PRIVATE (DECL_TEMPLATE_RESULT (decl)) = TREE_PRIVATE (decl);
TREE_PROTECTED (DECL_TEMPLATE_RESULT (decl)) = TREE_PROTECTED (decl);
}
DECL_CONTEXT (decl) = current_class_type;
if (DECL_LANG_SPECIFIC (decl) && DECL_LANGUAGE (decl) == lang_c)
SET_DECL_LANGUAGE (decl, lang_cplusplus);
if (TREE_CODE (decl) == FUNCTION_DECL
|| DECL_FUNCTION_TEMPLATE_P (decl))
{
if (add_method (current_class_type, decl, NULL_TREE))
{
TREE_CHAIN (decl) = TYPE_METHODS (current_class_type);
TYPE_METHODS (current_class_type) = decl;
maybe_add_class_template_decl_list (current_class_type, decl,
0);
}
}
else if ((TREE_CODE (decl) == USING_DECL && !DECL_DEPENDENT_P (decl))
|| pushdecl_class_level (decl))
{
if (TREE_CODE (decl) == TYPE_DECL)
TYPE_FIELDS (current_class_type)
= chainon (TYPE_FIELDS (current_class_type), decl);
else
{
TREE_CHAIN (decl) = TYPE_FIELDS (current_class_type);
TYPE_FIELDS (current_class_type) = decl;
}
maybe_add_class_template_decl_list (current_class_type, decl,
0);
}
if (pch_file)
note_decl_for_pch (decl);
}
void
note_decl_for_pch (tree decl)
{
gcc_assert (pch_file);
if ((TREE_CODE (decl) == VAR_DECL
|| TREE_CODE (decl) == FUNCTION_DECL)
&& !processing_template_decl)
mangle_decl (decl);
}
void
finish_template_decl (tree parms)
{
if (parms)
end_template_decl ();
else
end_specialization ();
}
tree
finish_template_type (tree name, tree args, int entering_scope)
{
tree decl;
decl = lookup_template_class (name, args,
NULL_TREE, NULL_TREE, entering_scope,
tf_warning_or_error | tf_user);
if (decl != error_mark_node)
decl = TYPE_STUB_DECL (decl);
return decl;
}
tree
finish_base_specifier (tree base, tree access, bool virtual_p)
{
tree result;
if (base == error_mark_node)
{
error ("invalid base-class specification");
result = NULL_TREE;
}
else if (! is_aggr_type (base, 1))
result = NULL_TREE;
else
{
if (cp_type_quals (base) != 0)
{
error ("base class %qT has cv qualifiers", base);
base = TYPE_MAIN_VARIANT (base);
}
result = build_tree_list (access, base);
if (virtual_p)
TREE_TYPE (result) = integer_type_node;
}
return result;
}
void
qualified_name_lookup_error (tree scope, tree name, tree decl)
{
if (scope == error_mark_node)
;
else if (TYPE_P (scope))
{
if (!COMPLETE_TYPE_P (scope))
error ("incomplete type %qT used in nested name specifier", scope);
else if (TREE_CODE (decl) == TREE_LIST)
{
error ("reference to %<%T::%D%> is ambiguous", scope, name);
print_candidates (decl);
}
else
error ("%qD is not a member of %qT", name, scope);
}
else if (scope != global_namespace)
error ("%qD is not a member of %qD", name, scope);
else
error ("%<::%D%> has not been declared", name);
}
tree
baselink_for_fns (tree fns)
{
tree fn;
tree cl;
if (BASELINK_P (fns)
|| error_operand_p (fns))
return fns;
fn = fns;
if (TREE_CODE (fn) == TEMPLATE_ID_EXPR)
fn = TREE_OPERAND (fn, 0);
fn = get_first_fn (fn);
if (!DECL_FUNCTION_MEMBER_P (fn))
return fns;
cl = currently_open_derived_class (DECL_CONTEXT (fn));
if (!cl)
cl = DECL_CONTEXT (fn);
cl = TYPE_BINFO (cl);
return build_baselink (cl, cl, fns, NULL_TREE);
}
tree
finish_id_expression (tree id_expression,
tree decl,
tree scope,
cp_id_kind *idk,
bool integral_constant_expression_p,
bool allow_non_integral_constant_expression_p,
bool *non_integral_constant_expression_p,
bool template_p,
bool done,
bool address_p,
bool template_arg_p,
const char **error_msg)
{
*idk = CP_ID_KIND_NONE;
*error_msg = NULL;
if (id_expression == error_mark_node)
return error_mark_node;
else if (TREE_CODE (decl) == TEMPLATE_ID_EXPR
|| TREE_CODE (decl) == TYPE_DECL)
;
else
{
if (decl == error_mark_node)
{
if (inside_iasm_block)
return iasm_do_id (id_expression);
if (scope
&& (!TYPE_P (scope)
|| (!dependent_type_p (scope)
&& !(TREE_CODE (id_expression) == IDENTIFIER_NODE
&& IDENTIFIER_TYPENAME_P (id_expression)
&& dependent_type_p (TREE_TYPE (id_expression))))))
{
qualified_name_lookup_error (scope, id_expression, decl);
return error_mark_node;
}
else if (!scope)
{
*idk = CP_ID_KIND_UNQUALIFIED;
return id_expression;
}
else
decl = id_expression;
}
else
decl = check_for_out_of_scope_variable (decl);
if (!scope && decl != error_mark_node)
maybe_note_name_used_in_class (id_expression, decl);
if (TREE_CODE (decl) == VAR_DECL || TREE_CODE (decl) == PARM_DECL)
{
tree context = decl_function_context (decl);
if (context != NULL_TREE && context != current_function_decl
&& ! TREE_STATIC (decl))
{
error (TREE_CODE (decl) == VAR_DECL
? "use of %<auto%> variable from containing function"
: "use of parameter from containing function");
error (" %q+#D declared here", decl);
return error_mark_node;
}
}
}
if (TREE_CODE (decl) == TEMPLATE_DECL
&& !DECL_FUNCTION_TEMPLATE_P (decl))
{
*error_msg = "missing template arguments";
return error_mark_node;
}
else if (TREE_CODE (decl) == TYPE_DECL && inside_iasm_block)
{
*idk = CP_ID_KIND_NONE;
return decl;
}
else if (TREE_CODE (decl) == TYPE_DECL
|| TREE_CODE (decl) == NAMESPACE_DECL)
{
*error_msg = "expected primary-expression";
return error_mark_node;
}
if ((TREE_CODE (decl) == CONST_DECL && DECL_TEMPLATE_PARM_P (decl))
|| TREE_CODE (decl) == TEMPLATE_PARM_INDEX)
{
tree r;
*idk = CP_ID_KIND_NONE;
if (TREE_CODE (decl) == TEMPLATE_PARM_INDEX)
decl = TEMPLATE_PARM_DECL (decl);
r = convert_from_reference (DECL_INITIAL (decl));
if (integral_constant_expression_p
&& !dependent_type_p (TREE_TYPE (decl))
&& !(INTEGRAL_OR_ENUMERATION_TYPE_P (TREE_TYPE (r))))
{
if (!allow_non_integral_constant_expression_p)
error ("template parameter %qD of type %qT is not allowed in "
"an integral constant expression because it is not of "
"integral or enumeration type", decl, TREE_TYPE (decl));
*non_integral_constant_expression_p = true;
}
return r;
}
else if (TREE_CODE (decl) == CONST_DECL)
{
*idk = CP_ID_KIND_NONE;
if (!processing_template_decl)
{
used_types_insert (TREE_TYPE (decl));
return DECL_INITIAL (decl);
}
return decl;
}
else
{
bool dependent_p;
*idk = (scope
? CP_ID_KIND_QUALIFIED
: (TREE_CODE (decl) == TEMPLATE_ID_EXPR
? CP_ID_KIND_TEMPLATE_ID
: CP_ID_KIND_UNQUALIFIED));
dependent_p = false;
if (!processing_template_decl)
;
else if (TREE_CODE (decl) == TEMPLATE_ID_EXPR
&& (TREE_CODE (TREE_OPERAND (decl, 0))
== IDENTIFIER_NODE))
dependent_p = true;
else if (!is_overloaded_fn (decl))
dependent_p
= dependent_type_p (TREE_TYPE (decl));
else
{
tree fns = decl;
if (BASELINK_P (fns))
fns = BASELINK_FUNCTIONS (fns);
if (TREE_CODE (fns) == TEMPLATE_ID_EXPR)
{
tree args = TREE_OPERAND (fns, 1);
dependent_p = any_dependent_template_arguments_p (args);
fns = TREE_OPERAND (fns, 0);
}
while (fns && !dependent_p)
{
tree fn = OVL_CURRENT (fns);
if (TREE_CODE (fn) == FUNCTION_DECL
&& type_dependent_expression_p (fn))
dependent_p = true;
else if (TREE_CODE (fn) == TEMPLATE_DECL
&& dependent_template_p (fn))
dependent_p = true;
fns = OVL_NEXT (fns);
}
}
if (dependent_p)
{
if (scope)
{
if (integral_constant_expression_p)
*non_integral_constant_expression_p = true;
if (TYPE_P (scope))
{
if (address_p && done)
decl = finish_qualified_id_expr (scope, decl,
done, address_p,
template_p,
template_arg_p);
else if (dependent_type_p (scope))
decl = build_qualified_name (NULL_TREE,
scope,
id_expression,
template_p);
else if (DECL_P (decl))
decl = build_qualified_name (TREE_TYPE (decl),
scope,
id_expression,
template_p);
}
if (TREE_TYPE (decl))
decl = convert_from_reference (decl);
return decl;
}
if (TREE_CODE (id_expression) == TEMPLATE_ID_EXPR)
return id_expression;
*idk = CP_ID_KIND_UNQUALIFIED_DEPENDENT;
if (TREE_CODE (decl) == VAR_DECL
|| TREE_CODE (decl) == PARM_DECL)
return convert_from_reference (decl);
else if (TREE_CODE (decl) == FIELD_DECL)
{
push_deferring_access_checks (dk_no_check);
decl = finish_non_static_data_member
(decl, current_class_ref,
NULL_TREE);
pop_deferring_access_checks ();
return decl;
}
return id_expression;
}
if (integral_constant_expression_p
&& ! DECL_INTEGRAL_CONSTANT_VAR_P (decl)
&& ! builtin_valid_in_constant_expr_p (decl))
{
if (!allow_non_integral_constant_expression_p)
{
error ("%qD cannot appear in a constant-expression", decl);
return error_mark_node;
}
*non_integral_constant_expression_p = true;
}
if (TREE_CODE (decl) == NAMESPACE_DECL)
{
error ("use of namespace %qD as expression", decl);
return error_mark_node;
}
else if (DECL_CLASS_TEMPLATE_P (decl))
{
error ("use of class template %qT as expression", decl);
return error_mark_node;
}
else if (TREE_CODE (decl) == TREE_LIST)
{
error ("request for member %qD is ambiguous in "
"multiple inheritance lattice", id_expression);
print_candidates (decl);
return error_mark_node;
}
if (TREE_CODE (decl) == VAR_DECL
|| TREE_CODE (decl) == PARM_DECL
|| TREE_CODE (decl) == RESULT_DECL)
mark_used (decl);
if (scope)
{
decl = (adjust_result_of_qualified_name_lookup
(decl, scope, current_class_type));
if (TREE_CODE (decl) == FUNCTION_DECL)
mark_used (decl);
if (TREE_CODE (decl) == FIELD_DECL || BASELINK_P (decl))
decl = finish_qualified_id_expr (scope,
decl,
done,
address_p,
template_p,
template_arg_p);
else
{
tree r = convert_from_reference (decl);
if (processing_template_decl && TYPE_P (scope))
r = build_qualified_name (TREE_TYPE (r),
scope, decl,
template_p);
decl = r;
}
}
else if (TREE_CODE (decl) == FIELD_DECL)
{
push_deferring_access_checks (dk_no_check);
decl = finish_non_static_data_member (decl, current_class_ref,
NULL_TREE);
pop_deferring_access_checks ();
}
else if (is_overloaded_fn (decl))
{
tree first_fn;
first_fn = decl;
if (TREE_CODE (first_fn) == TEMPLATE_ID_EXPR)
first_fn = TREE_OPERAND (first_fn, 0);
first_fn = get_first_fn (first_fn);
if (TREE_CODE (first_fn) == TEMPLATE_DECL)
first_fn = DECL_TEMPLATE_RESULT (first_fn);
if (!really_overloaded_fn (decl))
mark_used (first_fn);
if (!template_arg_p
&& TREE_CODE (first_fn) == FUNCTION_DECL
&& DECL_FUNCTION_MEMBER_P (first_fn)
&& !shared_member_p (decl))
{
decl = maybe_dummy_object (DECL_CONTEXT (first_fn), 0);
return finish_class_member_access_expr (decl, id_expression,
false);
}
decl = baselink_for_fns (decl);
}
else
{
if (DECL_P (decl) && DECL_NONLOCAL (decl)
&& DECL_CLASS_SCOPE_P (decl)
&& DECL_CONTEXT (decl) != current_class_type)
{
tree path;
path = currently_open_derived_class (DECL_CONTEXT (decl));
perform_or_defer_access_check (TYPE_BINFO (path), decl, decl);
}
decl = convert_from_reference (decl);
}
}
if (TREE_DEPRECATED (decl))
warn_deprecated_use (decl);
return decl;
}
tree
finish_typeof (tree expr)
{
tree type;
if (type_dependent_expression_p (expr))
{
type = make_aggr_type (TYPEOF_TYPE);
TYPEOF_TYPE_EXPR (type) = expr;
return type;
}
type = unlowered_expr_type (expr);
if (!type || type == unknown_type_node)
{
error ("type of %qE is unknown", expr);
return error_mark_node;
}
return type;
}
tree
finish_offsetof (tree expr)
{
if (TREE_CODE (expr) == PSEUDO_DTOR_EXPR)
{
error ("cannot apply %<offsetof%> to destructor %<~%T%>",
TREE_OPERAND (expr, 2));
return error_mark_node;
}
if (TREE_CODE (TREE_TYPE (expr)) == FUNCTION_TYPE
|| TREE_CODE (TREE_TYPE (expr)) == METHOD_TYPE
|| TREE_CODE (TREE_TYPE (expr)) == UNKNOWN_TYPE)
{
if (TREE_CODE (expr) == COMPONENT_REF
|| TREE_CODE (expr) == COMPOUND_EXPR)
expr = TREE_OPERAND (expr, 1);
error ("cannot apply %<offsetof%> to member function %qD", expr);
return error_mark_node;
}
return fold_offsetof (expr, NULL_TREE);
}
static tree
simplify_aggr_init_exprs_r (tree* tp,
int* walk_subtrees,
void* data ATTRIBUTE_UNUSED)
{
if (TYPE_P (*tp))
{
*walk_subtrees = 0;
return NULL_TREE;
}
else if (TREE_CODE (*tp) != AGGR_INIT_EXPR)
return NULL_TREE;
simplify_aggr_init_expr (tp);
return NULL_TREE;
}
void
simplify_aggr_init_expr (tree *tp)
{
tree aggr_init_expr = *tp;
tree fn = TREE_OPERAND (aggr_init_expr, 0);
tree args = TREE_OPERAND (aggr_init_expr, 1);
tree slot = TREE_OPERAND (aggr_init_expr, 2);
tree type = TREE_TYPE (slot);
tree call_expr;
enum style_t { ctor, arg, pcc } style;
if (AGGR_INIT_VIA_CTOR_P (aggr_init_expr))
style = ctor;
#ifdef PCC_STATIC_STRUCT_RETURN
else if (1)
style = pcc;
#endif
else
{
gcc_assert (TREE_ADDRESSABLE (type));
style = arg;
}
if (style == ctor)
{
tree addr;
args = TREE_CHAIN (args);
cxx_mark_addressable (slot);
addr = build1 (ADDR_EXPR, build_pointer_type (type), slot);
args = tree_cons (NULL_TREE, addr, args);
}
call_expr = build3 (CALL_EXPR,
TREE_TYPE (TREE_TYPE (TREE_TYPE (fn))),
fn, args, NULL_TREE);
if (style == arg)
{
cxx_mark_addressable (slot);
CALL_EXPR_RETURN_SLOT_OPT (call_expr) = true;
call_expr = build2 (MODIFY_EXPR, TREE_TYPE (call_expr), slot, call_expr);
}
else if (style == pcc)
{
push_deferring_access_checks (dk_no_check);
call_expr = build_aggr_init (slot, call_expr,
DIRECT_BIND | LOOKUP_ONLYCONVERTING);
pop_deferring_access_checks ();
call_expr = build2 (COMPOUND_EXPR, TREE_TYPE (slot), call_expr, slot);
}
*tp = call_expr;
}
static void
emit_associated_thunks (tree fn)
{
if (DECL_VIRTUAL_P (fn))
{
tree thunk;
for (thunk = DECL_THUNKS (fn); thunk; thunk = TREE_CHAIN (thunk))
{
if (!THUNK_ALIAS (thunk))
{
use_thunk (thunk, 1);
if (DECL_RESULT_THUNK_P (thunk))
{
tree probe;
for (probe = DECL_THUNKS (thunk);
probe; probe = TREE_CHAIN (probe))
use_thunk (probe, 1);
}
}
else
gcc_assert (!DECL_THUNKS (thunk));
}
}
}
void
expand_body (tree fn)
{
tree saved_function;
if (DECL_DECLARED_INLINE_P (fn))
import_export_decl (fn);
if (DECL_EXTERNAL (fn))
return;
saved_function = current_function_decl;
emit_associated_thunks (fn);
gcc_assert (function_depth == 0);
tree_rest_of_compilation (fn);
current_function_decl = saved_function;
if (DECL_CLONED_FUNCTION_P (fn))
{
tree probe;
for (probe = TREE_CHAIN (DECL_CLONED_FUNCTION (fn));
probe && DECL_CLONED_FUNCTION_P (probe);
probe = TREE_CHAIN (probe))
{
tree parms;
for (parms = DECL_ARGUMENTS (probe);
parms; parms = TREE_CHAIN (parms))
TREE_USED (parms) = 1;
}
}
}
void
expand_or_defer_fn (tree fn)
{
if (processing_template_decl)
{
if (!function_depth)
ggc_collect ();
return;
}
walk_tree_without_duplicates (&DECL_SAVED_TREE (fn),
simplify_aggr_init_exprs_r,
NULL);
if (maybe_clone_body (fn))
{
TREE_ASM_WRITTEN (fn) = 1;
return;
}
if (DECL_STATIC_CONSTRUCTOR (fn))
static_ctors = tree_cons (NULL_TREE, fn, static_ctors);
if (DECL_STATIC_DESTRUCTOR (fn))
static_dtors = tree_cons (NULL_TREE, fn, static_dtors);
if (DECL_DECLARED_INLINE_P (fn) || DECL_IMPLICIT_INSTANTIATION (fn))
{
if (DECL_INTERFACE_KNOWN (fn))
;
else if (!at_eof)
{
DECL_EXTERNAL (fn) = 1;
DECL_NOT_REALLY_EXTERN (fn) = 1;
note_vague_linkage_fn (fn);
if (!DECL_IMPLICIT_INSTANTIATION (fn))
{
gcc_assert (TREE_PUBLIC (fn));
comdat_linkage (fn);
DECL_INTERFACE_KNOWN (fn) = 1;
}
}
else
import_export_decl (fn);
if (flag_keep_inline_functions && DECL_DECLARED_INLINE_P (fn))
mark_needed (fn);
}
if (flag_syntax_only)
return;
function_depth++;
cgraph_finalize_function (fn, function_depth > 1);
function_depth--;
}
struct nrv_data
{
tree var;
tree result;
htab_t visited;
};
static tree
finalize_nrv_r (tree* tp, int* walk_subtrees, void* data)
{
struct nrv_data *dp = (struct nrv_data *)data;
void **slot;
if (TYPE_P (*tp))
*walk_subtrees = 0;
else if (TREE_CODE (*tp) == RETURN_EXPR)
TREE_OPERAND (*tp, 0) = dp->result;
else if (TREE_CODE (*tp) == CLEANUP_STMT
&& CLEANUP_DECL (*tp) == dp->var)
CLEANUP_EH_ONLY (*tp) = 1;
else if (TREE_CODE (*tp) == DECL_EXPR
&& DECL_EXPR_DECL (*tp) == dp->var)
{
tree init;
if (DECL_INITIAL (dp->var)
&& DECL_INITIAL (dp->var) != error_mark_node)
{
init = build2 (INIT_EXPR, void_type_node, dp->result,
DECL_INITIAL (dp->var));
DECL_INITIAL (dp->var) = error_mark_node;
}
else
init = build_empty_stmt ();
SET_EXPR_LOCUS (init, EXPR_LOCUS (*tp));
*tp = init;
}
else if (*tp == dp->var)
*tp = dp->result;
slot = htab_find_slot (dp->visited, *tp, INSERT);
if (*slot)
*walk_subtrees = 0;
else
*slot = *tp;
return NULL_TREE;
}
void
finalize_nrv (tree *tp, tree var, tree result)
{
struct nrv_data data;
DECL_NAME (result) = DECL_NAME (var);
DECL_ARTIFICIAL (result) = DECL_ARTIFICIAL (var);
DECL_IGNORED_P (result) = DECL_IGNORED_P (var);
DECL_SOURCE_LOCATION (result) = DECL_SOURCE_LOCATION (var);
DECL_ABSTRACT_ORIGIN (result) = DECL_ABSTRACT_ORIGIN (var);
TREE_ADDRESSABLE (result) = TREE_ADDRESSABLE (var);
data.var = var;
data.result = result;
data.visited = htab_create (37, htab_hash_pointer, htab_eq_pointer, NULL);
walk_tree (tp, finalize_nrv_r, &data, 0);
htab_delete (data.visited);
}
tree
finish_omp_clauses (tree clauses)
{
bitmap_head generic_head, firstprivate_head, lastprivate_head;
tree c, t, *pc = &clauses;
const char *name;
bitmap_obstack_initialize (NULL);
bitmap_initialize (&generic_head, &bitmap_default_obstack);
bitmap_initialize (&firstprivate_head, &bitmap_default_obstack);
bitmap_initialize (&lastprivate_head, &bitmap_default_obstack);
for (pc = &clauses, c = clauses; c ; c = *pc)
{
bool remove = false;
switch (OMP_CLAUSE_CODE (c))
{
case OMP_CLAUSE_SHARED:
name = "shared";
goto check_dup_generic;
case OMP_CLAUSE_PRIVATE:
name = "private";
goto check_dup_generic;
case OMP_CLAUSE_REDUCTION:
name = "reduction";
goto check_dup_generic;
case OMP_CLAUSE_COPYPRIVATE:
name = "copyprivate";
goto check_dup_generic;
case OMP_CLAUSE_COPYIN:
name = "copyin";
goto check_dup_generic;
check_dup_generic:
t = OMP_CLAUSE_DECL (c);
if (TREE_CODE (t) != VAR_DECL && TREE_CODE (t) != PARM_DECL)
{
if (processing_template_decl)
break;
if (DECL_P (t))
error ("%qD is not a variable in clause %qs", t, name);
else
error ("%qE is not a variable in clause %qs", t, name);
remove = true;
}
else if (bitmap_bit_p (&generic_head, DECL_UID (t))
|| bitmap_bit_p (&firstprivate_head, DECL_UID (t))
|| bitmap_bit_p (&lastprivate_head, DECL_UID (t)))
{
error ("%qD appears more than once in data clauses", t);
remove = true;
}
else
bitmap_set_bit (&generic_head, DECL_UID (t));
break;
case OMP_CLAUSE_FIRSTPRIVATE:
t = OMP_CLAUSE_DECL (c);
if (TREE_CODE (t) != VAR_DECL && TREE_CODE (t) != PARM_DECL)
{
if (processing_template_decl)
break;
error ("%qE is not a variable in clause %<firstprivate%>", t);
remove = true;
}
else if (bitmap_bit_p (&generic_head, DECL_UID (t))
|| bitmap_bit_p (&firstprivate_head, DECL_UID (t)))
{
error ("%qE appears more than once in data clauses", t);
remove = true;
}
else
bitmap_set_bit (&firstprivate_head, DECL_UID (t));
break;
case OMP_CLAUSE_LASTPRIVATE:
t = OMP_CLAUSE_DECL (c);
if (TREE_CODE (t) != VAR_DECL && TREE_CODE (t) != PARM_DECL)
{
if (processing_template_decl)
break;
error ("%qE is not a variable in clause %<lastprivate%>", t);
remove = true;
}
else if (bitmap_bit_p (&generic_head, DECL_UID (t))
|| bitmap_bit_p (&lastprivate_head, DECL_UID (t)))
{
error ("%qE appears more than once in data clauses", t);
remove = true;
}
else
bitmap_set_bit (&lastprivate_head, DECL_UID (t));
break;
case OMP_CLAUSE_IF:
t = OMP_CLAUSE_IF_EXPR (c);
t = maybe_convert_cond (t);
if (t == error_mark_node)
remove = true;
OMP_CLAUSE_IF_EXPR (c) = t;
break;
case OMP_CLAUSE_NUM_THREADS:
t = OMP_CLAUSE_NUM_THREADS_EXPR (c);
if (t == error_mark_node)
remove = true;
else if (!INTEGRAL_TYPE_P (TREE_TYPE (t))
&& !type_dependent_expression_p (t))
{
error ("num_threads expression must be integral");
remove = true;
}
break;
case OMP_CLAUSE_SCHEDULE:
t = OMP_CLAUSE_SCHEDULE_CHUNK_EXPR (c);
if (t == NULL)
;
else if (t == error_mark_node)
remove = true;
else if (!INTEGRAL_TYPE_P (TREE_TYPE (t))
&& !type_dependent_expression_p (t))
{
error ("schedule chunk size expression must be integral");
remove = true;
}
break;
case OMP_CLAUSE_NOWAIT:
case OMP_CLAUSE_ORDERED:
case OMP_CLAUSE_DEFAULT:
break;
default:
gcc_unreachable ();
}
if (remove)
*pc = OMP_CLAUSE_CHAIN (c);
else
pc = &OMP_CLAUSE_CHAIN (c);
}
for (pc = &clauses, c = clauses; c ; c = *pc)
{
enum tree_code c_kind = OMP_CLAUSE_CODE (c);
bool remove = false;
bool need_complete_non_reference = false;
bool need_default_ctor = false;
bool need_copy_ctor = false;
bool need_copy_assignment = false;
bool need_implicitly_determined = false;
tree type, inner_type;
switch (c_kind)
{
case OMP_CLAUSE_SHARED:
name = "shared";
need_implicitly_determined = true;
break;
case OMP_CLAUSE_PRIVATE:
name = "private";
need_complete_non_reference = true;
need_default_ctor = true;
need_implicitly_determined = true;
break;
case OMP_CLAUSE_FIRSTPRIVATE:
name = "firstprivate";
need_complete_non_reference = true;
need_copy_ctor = true;
need_implicitly_determined = true;
break;
case OMP_CLAUSE_LASTPRIVATE:
name = "lastprivate";
need_complete_non_reference = true;
need_copy_assignment = true;
need_implicitly_determined = true;
break;
case OMP_CLAUSE_REDUCTION:
name = "reduction";
need_implicitly_determined = true;
break;
case OMP_CLAUSE_COPYPRIVATE:
name = "copyprivate";
need_copy_assignment = true;
break;
case OMP_CLAUSE_COPYIN:
name = "copyin";
need_copy_assignment = true;
break;
default:
pc = &OMP_CLAUSE_CHAIN (c);
continue;
}
t = OMP_CLAUSE_DECL (c);
if (processing_template_decl
&& TREE_CODE (t) != VAR_DECL && TREE_CODE (t) != PARM_DECL)
{
pc = &OMP_CLAUSE_CHAIN (c);
continue;
}
switch (c_kind)
{
case OMP_CLAUSE_LASTPRIVATE:
if (!bitmap_bit_p (&firstprivate_head, DECL_UID (t)))
need_default_ctor = true;
break;
case OMP_CLAUSE_REDUCTION:
if (AGGREGATE_TYPE_P (TREE_TYPE (t))
|| POINTER_TYPE_P (TREE_TYPE (t)))
{
error ("%qE has invalid type for %<reduction%>", t);
remove = true;
}
else if (FLOAT_TYPE_P (TREE_TYPE (t)))
{
enum tree_code r_code = OMP_CLAUSE_REDUCTION_CODE (c);
switch (r_code)
{
case PLUS_EXPR:
case MULT_EXPR:
case MINUS_EXPR:
break;
default:
error ("%qE has invalid type for %<reduction(%s)%>",
t, operator_name_info[r_code].name);
remove = true;
}
}
break;
case OMP_CLAUSE_COPYIN:
if (TREE_CODE (t) != VAR_DECL || !DECL_THREAD_LOCAL_P (t))
{
error ("%qE must be %<threadprivate%> for %<copyin%>", t);
remove = true;
}
break;
default:
break;
}
if (need_complete_non_reference)
{
t = require_complete_type (t);
if (t == error_mark_node)
remove = true;
else if (TREE_CODE (TREE_TYPE (t)) == REFERENCE_TYPE)
{
error ("%qE has reference type for %qs", t, name);
remove = true;
}
}
if (need_implicitly_determined)
{
const char *share_name = NULL;
if (TREE_CODE (t) == VAR_DECL && DECL_THREAD_LOCAL_P (t))
share_name = "threadprivate";
else switch (cxx_omp_predetermined_sharing (t))
{
case OMP_CLAUSE_DEFAULT_UNSPECIFIED:
break;
case OMP_CLAUSE_DEFAULT_SHARED:
share_name = "shared";
break;
case OMP_CLAUSE_DEFAULT_PRIVATE:
share_name = "private";
break;
default:
gcc_unreachable ();
}
if (share_name)
{
error ("%qE is predetermined %qs for %qs",
t, share_name, name);
remove = true;
}
}
inner_type = type = TREE_TYPE (t);
while (TREE_CODE (inner_type) == ARRAY_TYPE)
inner_type = TREE_TYPE (inner_type);
if (CLASS_TYPE_P (inner_type)
&& (need_default_ctor || need_copy_ctor || need_copy_assignment)
&& !type_dependent_expression_p (t))
{
int save_errorcount = errorcount;
tree info;
info = make_tree_vec (3);
CP_OMP_CLAUSE_INFO (c) = info;
if (need_default_ctor
|| (need_copy_ctor
&& !TYPE_HAS_TRIVIAL_INIT_REF (inner_type)))
{
if (need_default_ctor)
t = NULL;
else
{
t = build_int_cst (build_pointer_type (inner_type), 0);
t = build1 (INDIRECT_REF, inner_type, t);
t = build_tree_list (NULL, t);
}
t = build_special_member_call (NULL_TREE,
complete_ctor_identifier,
t, inner_type, LOOKUP_NORMAL);
t = get_callee_fndecl (t);
TREE_VEC_ELT (info, 0) = t;
}
if ((need_default_ctor || need_copy_ctor)
&& TYPE_HAS_NONTRIVIAL_DESTRUCTOR (inner_type))
{
t = build_int_cst (build_pointer_type (inner_type), 0);
t = build1 (INDIRECT_REF, inner_type, t);
t = build_special_member_call (t, complete_dtor_identifier,
NULL, inner_type, LOOKUP_NORMAL);
t = get_callee_fndecl (t);
TREE_VEC_ELT (info, 1) = t;
}
if (need_copy_assignment
&& !TYPE_HAS_TRIVIAL_ASSIGN_REF (inner_type))
{
t = build_int_cst (build_pointer_type (inner_type), 0);
t = build1 (INDIRECT_REF, inner_type, t);
t = build_special_member_call (t, ansi_assopname (NOP_EXPR),
build_tree_list (NULL, t),
inner_type, LOOKUP_NORMAL);
if (TREE_CODE (t) == INDIRECT_REF)
t = TREE_OPERAND (t, 0);
t = get_callee_fndecl (t);
TREE_VEC_ELT (info, 2) = t;
}
if (errorcount != save_errorcount)
remove = true;
}
if (remove)
*pc = OMP_CLAUSE_CHAIN (c);
else
pc = &OMP_CLAUSE_CHAIN (c);
}
bitmap_obstack_release (NULL);
return clauses;
}
void
finish_omp_threadprivate (tree vars)
{
tree t;
for (t = vars; t; t = TREE_CHAIN (t))
{
tree v = TREE_PURPOSE (t);
if (TREE_USED (v)
&& (DECL_LANG_SPECIFIC (v) == NULL
|| !CP_DECL_THREADPRIVATE_P (v)))
error ("%qE declared %<threadprivate%> after first use", v);
else if (! TREE_STATIC (v) && ! DECL_EXTERNAL (v))
error ("automatic variable %qE cannot be %<threadprivate%>", v);
else if (! COMPLETE_TYPE_P (TREE_TYPE (v)))
error ("%<threadprivate%> %qE has incomplete type", v);
else if (TREE_STATIC (v) && TYPE_P (CP_DECL_CONTEXT (v)))
error ("%<threadprivate%> %qE is not file, namespace "
"or block scope variable", v);
else
{
if (DECL_LANG_SPECIFIC (v) == NULL)
{
retrofit_lang_decl (v);
if (DECL_DISCRIMINATOR_P (v))
DECL_LANG_SPECIFIC (v)->decl_flags.u2sel = 1;
}
if (! DECL_THREAD_LOCAL_P (v))
{
DECL_TLS_MODEL (v) = decl_default_tls_model (v);
if (DECL_RTL_SET_P (v))
make_decl_rtl (v);
}
CP_DECL_THREADPRIVATE_P (v) = 1;
}
}
}
tree
begin_omp_structured_block (void)
{
return do_pushlevel (sk_omp);
}
tree
finish_omp_structured_block (tree block)
{
return do_poplevel (block);
}
tree
begin_omp_parallel (void)
{
keep_next_level (true);
return begin_omp_structured_block ();
}
tree
finish_omp_parallel (tree clauses, tree body)
{
tree stmt;
body = finish_omp_structured_block (body);
stmt = make_node (OMP_PARALLEL);
TREE_TYPE (stmt) = void_type_node;
OMP_PARALLEL_CLAUSES (stmt) = clauses;
OMP_PARALLEL_BODY (stmt) = body;
return add_stmt (stmt);
}
tree
finish_omp_for (location_t locus, tree decl, tree init, tree cond,
tree incr, tree body, tree pre_body)
{
if (decl == NULL)
{
if (init != NULL)
switch (TREE_CODE (init))
{
case MODIFY_EXPR:
decl = TREE_OPERAND (init, 0);
init = TREE_OPERAND (init, 1);
break;
case MODOP_EXPR:
if (TREE_CODE (TREE_OPERAND (init, 1)) == NOP_EXPR)
{
decl = TREE_OPERAND (init, 0);
init = TREE_OPERAND (init, 2);
}
break;
default:
break;
}
if (decl == NULL)
{
error ("expected iteration declaration or initialization");
return NULL;
}
}
if (type_dependent_expression_p (decl)
|| type_dependent_expression_p (init)
|| (cond && type_dependent_expression_p (cond))
|| (incr && type_dependent_expression_p (incr)))
{
tree stmt;
if (cond == NULL)
{
error ("%Hmissing controlling predicate", &locus);
return NULL;
}
if (incr == NULL)
{
error ("%Hmissing increment expression", &locus);
return NULL;
}
stmt = make_node (OMP_FOR);
init = build2 (MODIFY_EXPR, void_type_node, decl, init);
TREE_TYPE (stmt) = void_type_node;
OMP_FOR_INIT (stmt) = init;
OMP_FOR_COND (stmt) = cond;
OMP_FOR_INCR (stmt) = incr;
OMP_FOR_BODY (stmt) = body;
OMP_FOR_PRE_BODY (stmt) = pre_body;
SET_EXPR_LOCATION (stmt, locus);
return add_stmt (stmt);
}
if (!DECL_P (decl))
{
error ("expected iteration declaration or initialization");
return NULL;
}
if (pre_body == NULL || IS_EMPTY_STMT (pre_body))
pre_body = NULL;
else if (! processing_template_decl)
{
add_stmt (pre_body);
pre_body = NULL;
}
init = build_modify_expr (decl, NOP_EXPR, init);
return c_finish_omp_for (locus, decl, init, cond, incr, body, pre_body);
}
void
finish_omp_atomic (enum tree_code code, tree lhs, tree rhs)
{
tree orig_lhs;
tree orig_rhs;
bool dependent_p;
tree stmt;
orig_lhs = lhs;
orig_rhs = rhs;
dependent_p = false;
stmt = NULL_TREE;
if (processing_template_decl)
{
dependent_p = (type_dependent_expression_p (lhs)
|| type_dependent_expression_p (rhs));
if (!dependent_p)
{
lhs = build_non_dependent_expr (lhs);
rhs = build_non_dependent_expr (rhs);
}
}
if (!dependent_p)
{
stmt = c_finish_omp_atomic (code, lhs, rhs);
if (stmt == error_mark_node)
return;
}
if (processing_template_decl)
{
stmt = build2 (OMP_ATOMIC, void_type_node, orig_lhs, orig_rhs);
OMP_ATOMIC_DEPENDENT_P (stmt) = 1;
OMP_ATOMIC_CODE (stmt) = code;
}
add_stmt (stmt);
}
void
finish_omp_barrier (void)
{
tree fn = built_in_decls[BUILT_IN_GOMP_BARRIER];
tree stmt = finish_call_expr (fn, NULL, false, false);
finish_expr_stmt (stmt);
}
void
finish_omp_flush (void)
{
tree fn = built_in_decls[BUILT_IN_SYNCHRONIZE];
tree stmt = finish_call_expr (fn, NULL, false, false);
finish_expr_stmt (stmt);
}
enum omp_clause_default_kind
cxx_omp_predetermined_sharing (tree decl)
{
enum omp_clause_default_kind kind;
kind = c_omp_predetermined_sharing (decl);
if (kind != OMP_CLAUSE_DEFAULT_UNSPECIFIED)
return kind;
if (TREE_STATIC (decl))
{
tree ctx = CP_DECL_CONTEXT (decl);
if (TYPE_P (ctx) && IS_AGGR_TYPE (ctx))
return OMP_CLAUSE_DEFAULT_SHARED;
}
return OMP_CLAUSE_DEFAULT_UNSPECIFIED;
}
void
init_cp_semantics (void)
{
}
#include "gt-cp-semantics.h"