building RTL. These routines are used both during actual parsing
and during the instantiation of template functions.
- Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
- Free Software Foundation, Inc.
+ Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007,
+ 2008 Free Software Foundation, Inc.
Written by Mark Mitchell (mmitchell@usa.net) based on code found
formerly in parse.y and pt.c.
GCC is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2, or (at your option)
+ the Free Software Foundation; either version 3, or (at your option)
any later version.
GCC is distributed in the hope that it will be useful, but
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with GCC; see the file COPYING. If not, write to the Free
- Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
- 02110-1301, USA. */
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
#include "config.h"
#include "system.h"
/* There routines provide a modular interface to perform many parsing
operations. They may therefore be used during actual parsing, or
during template instantiation, which may be regarded as a
- degenerate form of parsing. Since the current g++ parser is
- lacking in several respects, and will be reimplemented, we are
- attempting to move most code that is not directly related to
- parsing into this file; that will make implementing the new parser
- much easier since it will be able to make use of these routines. */
+ degenerate form of parsing. */
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 *);
2. When a declaration such as a type, or a variable, is encountered,
the function `perform_or_defer_access_check' is called. It
- maintains a TREE_LIST of all deferred checks.
+ maintains a VEC of all deferred checks.
3. The global `current_class_type' or `current_function_decl' is then
setup by the parser. `enforce_access' relies on these information
4. Upon exiting the context mentioned in step 1,
`perform_deferred_access_checks' is called to check all declaration
- stored in the TREE_LIST. `pop_deferring_access_checks' is then
+ stored in the VEC. `pop_deferring_access_checks' is then
called to restore the previous access checking mode.
In case of parsing error, we simply call `pop_deferring_access_checks'
typedef struct deferred_access GTY(())
{
- /* A TREE_LIST representing name-lookups for which we have deferred
+ /* A VEC representing name-lookups for which we have deferred
checking access controls. We cannot check the accessibility of
names used in a decl-specifier-seq until we know what is being
declared because code like:
A::B* A::f() { return 0; }
- is valid, even though `A::B' is not generally accessible.
-
- The TREE_PURPOSE of each node is the scope used to qualify the
- name being looked up; the TREE_VALUE is the DECL to which the
- name was resolved. */
- tree deferred_access_checks;
+ is valid, even though `A::B' is not generally accessible. */
+ VEC (deferred_access_check,gc)* GTY(()) deferred_access_checks;
/* The current mode of access checks. */
enum deferring_kind deferring_access_checks_kind;
deferred_access *ptr;
ptr = VEC_safe_push (deferred_access, gc, deferred_access_stack, NULL);
- ptr->deferred_access_checks = NULL_TREE;
+ ptr->deferred_access_checks = NULL;
ptr->deferring_access_checks_kind = deferring;
}
}
access occurred; the TREE_VALUE is the declaration named.
*/
-tree
+VEC (deferred_access_check,gc)*
get_deferred_access_checks (void)
{
if (deferred_access_no_check)
deferred_access_no_check--;
else
{
- tree checks;
+ VEC (deferred_access_check,gc) *checks;
deferred_access *ptr;
checks = (VEC_last (deferred_access, deferred_access_stack)
if (ptr->deferring_access_checks_kind == dk_no_deferred)
{
/* Check access. */
- for (; checks; checks = TREE_CHAIN (checks))
- enforce_access (TREE_PURPOSE (checks),
- TREE_VALUE (checks));
+ perform_access_checks (checks);
}
else
{
/* Merge with parent. */
- tree next;
- tree original = ptr->deferred_access_checks;
+ int i, j;
+ deferred_access_check *chk, *probe;
- for (; checks; checks = next)
+ for (i = 0 ;
+ VEC_iterate (deferred_access_check, checks, i, chk) ;
+ ++i)
{
- tree probe;
-
- next = TREE_CHAIN (checks);
-
- for (probe = original; probe; probe = TREE_CHAIN (probe))
- if (TREE_VALUE (probe) == TREE_VALUE (checks)
- && TREE_PURPOSE (probe) == TREE_PURPOSE (checks))
- goto found;
+ 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;
+ }
/* Insert into parent's checks. */
- TREE_CHAIN (checks) = ptr->deferred_access_checks;
- ptr->deferred_access_checks = checks;
+ VEC_safe_push (deferred_access_check, gc,
+ ptr->deferred_access_checks, chk);
found:;
}
}
}
}
+/* Perform the access checks in CHECKS. The TREE_PURPOSE of each node
+ is the BINFO indicating the qualifying scope used to access the
+ DECL node stored in the TREE_VALUE of the node. */
+
+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);
+}
+
/* Perform the deferred access checks.
After performing the checks, we still have to keep the list
void
perform_deferred_access_checks (void)
{
- tree deferred_check;
-
- for (deferred_check = get_deferred_access_checks ();
- deferred_check;
- deferred_check = TREE_CHAIN (deferred_check))
- /* Check access. */
- enforce_access (TREE_PURPOSE (deferred_check),
- TREE_VALUE (deferred_check));
+ perform_access_checks (get_deferred_access_checks ());
}
/* Defer checking the accessibility of DECL, when looked up in
- BINFO. */
+ BINFO. DIAG_DECL is the declaration to use to print diagnostics. */
void
-perform_or_defer_access_check (tree binfo, tree decl)
+perform_or_defer_access_check (tree binfo, tree decl, tree diag_decl)
{
- tree check;
+ int i;
deferred_access *ptr;
+ deferred_access_check *chk;
+ deferred_access_check *new_access;
+
/* Exit if we are in a context that no access checking is performed.
*/
/* If we are not supposed to defer access checks, just check now. */
if (ptr->deferring_access_checks_kind == dk_no_deferred)
{
- enforce_access (binfo, decl);
+ enforce_access (binfo, decl, diag_decl);
return;
}
/* See if we are already going to perform this check. */
- for (check = ptr->deferred_access_checks;
- check;
- check = TREE_CHAIN (check))
- if (TREE_VALUE (check) == decl && TREE_PURPOSE (check) == binfo)
- 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;
+ }
+ }
/* If not, record the check. */
- ptr->deferred_access_checks
- = tree_cons (binfo, decl, ptr->deferred_access_checks);
+ 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;
}
/* Returns nonzero if the current statement is a full expression,
declared is not an anonymous union" [class.union]. */
int
-anon_aggr_type_p (tree node)
+anon_aggr_type_p (const_tree node)
{
return ANON_AGGR_TYPE_P (node);
}
tree cond = pop_stmt_list (*cond_p);
if (TREE_CODE (cond) == DECL_EXPR)
expr = cond;
+
+ if (check_for_bare_parameter_packs (&expr))
+ *cond_p = error_mark_node;
}
*cond_p = expr;
}
/* Do the conversion. */
cond = convert_from_reference (cond);
+
+ if (TREE_CODE (cond) == MODIFY_EXPR
+ && !TREE_NO_WARNING (cond)
+ && warn_parentheses)
+ {
+ warning (OPT_Wparentheses,
+ "suggest parentheses around assignment used as truth value");
+ TREE_NO_WARNING (cond) = 1;
+ }
+
return condition_conversion (cond);
}
else if (!type_dependent_expression_p (expr))
convert_to_void (build_non_dependent_expr (expr), "statement");
+ if (check_for_bare_parameter_packs (&expr))
+ expr = error_mark_node;
+
/* Simplification of inner statement expressions, compound exprs,
etc can result in us already having an EXPR_STMT. */
if (TREE_CODE (expr) != CLEANUP_POINT_EXPR)
TREE_CHAIN (if_stmt) = NULL;
add_stmt (do_poplevel (scope));
finish_stmt ();
+ empty_if_body_warning (THEN_CLAUSE (if_stmt), ELSE_CLAUSE (if_stmt));
}
/* Begin a while-statement. Returns a newly created WHILE_STMT if
void
finish_do_body (tree do_stmt)
{
- DO_BODY (do_stmt) = pop_stmt_list (DO_BODY (do_stmt));
+ tree body = DO_BODY (do_stmt) = pop_stmt_list (DO_BODY (do_stmt));
+
+ if (TREE_CODE (body) == STATEMENT_LIST && STATEMENT_LIST_TAIL (body))
+ body = STATEMENT_LIST_TAIL (body)->stmt;
+
+ if (IS_EMPTY_STMT (body))
+ warning (OPT_Wempty_body,
+ "suggest explicit braces around empty body in %<do%> statement");
}
/* Finish a do-statement, which may be given by DO_STMT, and whose
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)
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);
+ if (check_for_bare_parameter_packs (&expr))
+ expr = error_mark_node;
FOR_EXPR (for_stmt) = expr;
}
cond = index;
}
}
+ if (check_for_bare_parameter_packs (&cond))
+ cond = error_mark_node;
finish_cond (&SWITCH_STMT_COND (switch_stmt), cond);
SWITCH_STMT_TYPE (switch_stmt) = orig_type;
add_stmt (switch_stmt);
return r;
}
-/* Likewise, for a function-try-block. */
+/* Likewise, for a function-try-block. The block returned in
+ *COMPOUND_STMT is an artificial outer scope, containing the
+ function-try-block. */
tree
-begin_function_try_block (void)
+begin_function_try_block (tree *compound_stmt)
{
- tree r = begin_try_block ();
+ tree r;
+ /* This outer scope does not exist in the C++ standard, but we need
+ a place to put __FUNCTION__ and similar variables. */
+ *compound_stmt = begin_compound_stmt (0);
+ r = begin_try_block ();
FN_TRY_BLOCK_P (r) = 1;
return r;
}
check_handlers (TRY_HANDLERS (try_block));
}
-/* Likewise, for a function-try-block. */
+/* Finish the handler-seq for a function-try-block, given by
+ TRY_BLOCK. COMPOUND_STMT is the outer block created by
+ begin_function_try_block. */
void
-finish_function_handler_sequence (tree try_block)
+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);
}
/* Begin a handler. Returns a HANDLER if appropriate. */
}
else
type = expand_start_catch_block (decl);
-
HANDLER_TYPE (handler) = type;
if (!processing_template_decl && type)
mark_used (eh_type_info (type));
if (!lvalue_or_else (operand, lv_asm))
operand = error_mark_node;
- if (operand != error_mark_node
+ if (operand != error_mark_node
&& (TREE_READONLY (operand)
|| CP_TYPE_CONST_P (TREE_TYPE (operand))
- /* Functions are not modifiable, even though they are
- lvalues. */
- || TREE_CODE (TREE_TYPE (operand)) == FUNCTION_TYPE
- || TREE_CODE (TREE_TYPE (operand)) == METHOD_TYPE
- /* If it's an aggregate and any field is const, then it is
- effectively const. */
- || (CLASS_TYPE_P (TREE_TYPE (operand))
- && C_TYPE_FIELDS_READONLY (TREE_TYPE (operand)))))
- readonly_error (operand, "assignment (via 'asm' output)", 0);
+ /* Functions are not modifiable, even though they are
+ lvalues. */
+ || TREE_CODE (TREE_TYPE (operand)) == FUNCTION_TYPE
+ || TREE_CODE (TREE_TYPE (operand)) == METHOD_TYPE
+ /* If it's an aggregate and any field is const, then it is
+ effectively const. */
+ || (CLASS_TYPE_P (TREE_TYPE (operand))
+ && C_TYPE_FIELDS_READONLY (TREE_TYPE (operand)))))
+ readonly_error (operand, "assignment (via 'asm' output)");
constraint = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (t)));
oconstraints[i] = constraint;
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);
+ if (!at_function_scope_p ())
+ {
+ error ("__label__ declarations are only allowed in function scopes");
+ return;
+ }
+
+ add_decl_expr (declare_local_label (name));
}
/* When DECL goes out of scope, make sure that CLEANUP is executed. */
mem_inits = nreverse (mem_inits);
if (processing_template_decl)
- add_stmt (build_min_nt (CTOR_INITIALIZER, mem_inits));
+ {
+ tree mem;
+
+ for (mem = mem_inits; mem; mem = TREE_CHAIN (mem))
+ {
+ /* If the TREE_PURPOSE is a TYPE_PACK_EXPANSION, skip the
+ check for bare parameter packs in the TREE_VALUE, because
+ any parameter packs in the TREE_VALUE have already been
+ bound as part of the TREE_PURPOSE. See
+ make_pack_expansion for more information. */
+ if (TREE_CODE (TREE_PURPOSE (mem)) != TYPE_PACK_EXPANSION
+ && check_for_bare_parameter_packs (&TREE_VALUE (mem)))
+ TREE_VALUE (mem) = error_mark_node;
+ }
+
+ add_stmt (build_min_nt (CTOR_INITIALIZER, mem_inits));
+ }
else
emit_mem_initializers (mem_inits);
}
DECL_NAME (decl),
/*template_p=*/false);
- perform_or_defer_access_check (TYPE_BINFO (access_type), decl);
+ perform_or_defer_access_check (TYPE_BINFO (access_type), decl,
+ decl);
/* If the data member was named `C::M', convert `*this' to `C'
first. */
its bases. */
qualifying_type = currently_open_derived_class (scope);
- if (qualifying_type && IS_AGGR_TYPE_CODE (TREE_CODE (qualifying_type)))
- /* It is possible for qualifying type to be a TEMPLATE_TYPE_PARM
- or similar in a default argument value. */
- perform_or_defer_access_check (TYPE_BINFO (qualifying_type), decl);
+ if (qualifying_type
+ /* It is possible for qualifying type to be a TEMPLATE_TYPE_PARM
+ or similar in a default argument value. */
+ && CLASS_TYPE_P (qualifying_type)
+ && !dependent_type_p (qualifying_type))
+ perform_or_defer_access_check (TYPE_BINFO (qualifying_type), decl,
+ decl);
}
/* EXPR is the result of a qualified-id. The QUALIFYING_CLASS was the
is true iff this qualified name appears as a template argument. */
tree
-finish_qualified_id_expr (tree qualifying_class,
- tree expr,
+finish_qualified_id_expr (tree qualifying_class,
+ tree expr,
bool done,
- bool address_p,
+ bool address_p,
bool template_p,
bool template_arg_p)
{
if (error_operand_p (expr))
return error_mark_node;
- if (DECL_P (expr))
+ if (DECL_P (expr) || BASELINK_P (expr))
mark_used (expr);
- else if (BASELINK_P (expr)
- && TREE_CODE (BASELINK_FUNCTIONS (expr)) != TEMPLATE_ID_EXPR
- && !really_overloaded_fn (BASELINK_FUNCTIONS (expr)))
- mark_used (OVL_CURRENT (BASELINK_FUNCTIONS (expr)));
if (template_p)
check_template_keyword (expr);
finish_stmt_expr_expr (tree expr, tree stmt_expr)
{
if (error_operand_p (expr))
- return error_mark_node;
+ {
+ /* The type of the statement-expression is the type of the last
+ expression. */
+ TREE_TYPE (stmt_expr) = error_mark_node;
+ return error_mark_node;
+ }
/* If the last statement does not have "void" type, then the value
- of the last statement is the value of the entire expression. */
+ of the last statement is the value of the entire expression. */
if (expr)
{
- tree type;
- type = TREE_TYPE (expr);
- if (!dependent_type_p (type) && !VOID_TYPE_P (type))
+ tree type = TREE_TYPE (expr);
+
+ if (processing_template_decl)
+ {
+ expr = build_stmt (EXPR_STMT, expr);
+ expr = add_stmt (expr);
+ /* Mark the last statement so that we can recognize it as such at
+ template-instantiation time. */
+ EXPR_STMT_STMT_EXPR_RESULT (expr) = 1;
+ }
+ else if (VOID_TYPE_P (type))
+ {
+ /* Just treat this like an ordinary statement. */
+ expr = finish_expr_stmt (expr);
+ }
+ else
{
- expr = decay_conversion (expr);
+ /* It actually has a value we need to deal with. First, force it
+ to be an rvalue so that we won't need to build up a copy
+ constructor call later when we try to assign it to something. */
+ expr = force_rvalue (expr);
if (error_operand_p (expr))
return error_mark_node;
+
+ /* Update for array-to-pointer decay. */
type = TREE_TYPE (expr);
+
+ /* Wrap it in a CLEANUP_POINT_EXPR and add it to the list like a
+ normal statement, but don't convert to void or actually add
+ the EXPR_STMT. */
+ if (TREE_CODE (expr) != CLEANUP_POINT_EXPR)
+ expr = maybe_cleanup_point_expr (expr);
+ add_stmt (expr);
}
+
/* The type of the statement-expression is the type of the last
expression. */
TREE_TYPE (stmt_expr) = type;
- /* We must take particular care if TYPE is a class type. In
- particular if EXPR creates a temporary of class type, then it
- must be destroyed at the semicolon terminating the last
- statement -- but we must make a copy before that happens.
-
- This problem is solved by using a TARGET_EXPR to initialize a
- new temporary variable. The TARGET_EXPR itself is placed
- outside the statement-expression. However, the last
- statement in the statement-expression is transformed from
- EXPR to (approximately) T = EXPR, where T is the new
- temporary variable. Thus, the lifetime of the new temporary
- extends to the full-expression surrounding the
- statement-expression. */
- if (!processing_template_decl && !VOID_TYPE_P (type))
- {
- tree target_expr;
- if (CLASS_TYPE_P (type)
- && !TYPE_HAS_TRIVIAL_INIT_REF (type))
- {
- target_expr = build_target_expr_with_type (expr, type);
- expr = TARGET_EXPR_INITIAL (target_expr);
- }
- else
- {
- /* Normally, build_target_expr will not create a
- TARGET_EXPR for scalars. However, we need the
- temporary here, in order to solve the scoping
- problem described above. */
- target_expr = force_target_expr (type, expr);
- expr = TARGET_EXPR_INITIAL (target_expr);
- expr = build2 (INIT_EXPR,
- type,
- TARGET_EXPR_SLOT (target_expr),
- expr);
- }
- TARGET_EXPR_INITIAL (target_expr) = NULL_TREE;
- /* Save away the TARGET_EXPR in the TREE_TYPE field of the
- STATEMENT_EXPR. We will retrieve it in
- finish_stmt_expr. */
- TREE_TYPE (stmt_expr) = target_expr;
- }
}
- /* Having modified EXPR to reflect the extra initialization, we now
- treat it just like an ordinary statement. */
- expr = finish_expr_stmt (expr);
-
- /* Mark the last statement so that we can recognize it as such at
- template-instantiation time. */
- if (expr && processing_template_decl)
- EXPR_STMT_STMT_EXPR_RESULT (expr) = 1;
-
return stmt_expr;
}
type = TREE_TYPE (stmt_expr);
result = pop_stmt_list (stmt_expr);
+ TREE_TYPE (result) = type;
if (processing_template_decl)
{
TREE_SIDE_EFFECTS (result) = 1;
STMT_EXPR_NO_SCOPE (result) = has_no_scope;
}
- else if (!TYPE_P (type))
+ else if (CLASS_TYPE_P (type))
{
- gcc_assert (TREE_CODE (type) == TARGET_EXPR);
- TARGET_EXPR_INITIAL (type) = result;
- TREE_TYPE (result) = void_type_node;
- result = type;
+ /* Wrap the statement-expression in a TARGET_EXPR so that the
+ temporary object created by the final expression is destroyed at
+ the end of the full-expression containing the
+ statement-expression. */
+ result = force_target_expr (type, result);
}
return result;
}
+/* Returns the expression which provides the value of STMT_EXPR. */
+
+tree
+stmt_expr_value_expr (tree stmt_expr)
+{
+ tree t = STMT_EXPR_STMT (stmt_expr);
+
+ if (TREE_CODE (t) == BIND_EXPR)
+ t = BIND_EXPR_BODY (t);
+
+ if (TREE_CODE (t) == STATEMENT_LIST)
+ t = STATEMENT_LIST_TAIL (t)->stmt;
+
+ if (TREE_CODE (t) == EXPR_STMT)
+ t = EXPR_STMT_EXPR (t);
+
+ return t;
+}
+
/* Perform Koenig lookup. FN is the postfix-expression representing
the function (or functions) to call; ARGS are the arguments to the
call. Returns the functions to be considered by overload
/* ARGS should be a list of arguments. */
gcc_assert (!args || TREE_CODE (args) == TREE_LIST);
+ gcc_assert (!TYPE_P (fn));
orig_fn = fn;
orig_args = args;
if (type_dependent_expression_p (fn)
|| any_type_dependent_arguments_p (args))
{
- result = build_nt (CALL_EXPR, fn, args, NULL_TREE);
+ result = build_nt_call_list (fn, args);
KOENIG_LOOKUP_P (result) = koenig_p;
+ if (cfun)
+ {
+ do
+ {
+ tree fndecl = OVL_CURRENT (fn);
+ if (TREE_CODE (fndecl) != FUNCTION_DECL
+ || !TREE_THIS_VOLATILE (fndecl))
+ break;
+ fn = OVL_NEXT (fn);
+ }
+ while (fn);
+ if (!fn)
+ current_function_returns_abnormally = 1;
+ }
return result;
}
if (!BASELINK_P (fn)
args = build_non_dependent_args (orig_args);
}
- /* A reference to a member function will appear as an overloaded
- function (rather than a BASELINK) if an unqualified name was used
- to refer to it. */
- if (!BASELINK_P (fn) && is_overloaded_fn (fn))
- {
- tree f = fn;
-
- if (TREE_CODE (f) == TEMPLATE_ID_EXPR)
- f = TREE_OPERAND (f, 0);
- f = get_first_fn (f);
- if (DECL_FUNCTION_MEMBER_P (f))
- {
- tree type = currently_open_derived_class (DECL_CONTEXT (f));
- if (!type)
- type = DECL_CONTEXT (f);
- fn = build_baselink (TYPE_BINFO (type),
- TYPE_BINFO (type),
- fn, /*optype=*/NULL_TREE);
- }
- }
+ if (is_overloaded_fn (fn))
+ fn = baselink_for_fns (fn);
result = NULL_TREE;
if (BASELINK_P (fn))
if (processing_template_decl)
{
if (type_dependent_expression_p (object))
- return build_nt (CALL_EXPR, orig_fn, orig_args, NULL_TREE);
+ return build_nt_call_list (orig_fn, orig_args);
object = build_non_dependent_expr (object);
}
result = build_new_method_call (object, fn, args, NULL_TREE,
(disallow_virtual
- ? LOOKUP_NONVIRTUAL : 0));
+ ? LOOKUP_NONVIRTUAL : 0),
+ /*fn_p=*/NULL);
}
else if (is_overloaded_fn (fn))
{
if (processing_template_decl)
{
- result = build3 (CALL_EXPR, TREE_TYPE (result), orig_fn,
- orig_args, NULL_TREE);
+ result = build_call_list (TREE_TYPE (result), orig_fn, orig_args);
KOENIG_LOOKUP_P (result) = koenig_p;
}
return result;
tree
finish_pseudo_destructor_expr (tree object, tree scope, tree destructor)
{
- if (destructor == error_mark_node)
+ if (object == error_mark_node || destructor == error_mark_node)
return error_mark_node;
gcc_assert (TYPE_P (destructor));
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;
+ }
+
/* [expr.pseudo] says both:
result = copy_node (result);
TREE_NEGATED_INT (result) = 1;
}
- overflow_warning (result);
+ if (TREE_OVERFLOW_P (result) && !TREE_OVERFLOW_P (expr))
+ 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;
+ }
+
/* Build a CONSTRUCTOR for the INITIALIZER_LIST. */
compound_literal = build_constructor (NULL_TREE, initializer_list);
- /* Mark it as a compound-literal. */
if (processing_template_decl)
- TREE_TYPE (compound_literal) = type;
- else
{
- /* Check the initialization. */
- compound_literal = digest_init (type, compound_literal);
- /* If the TYPE was an array type with an unknown bound, then we can
- figure out the dimension now. For example, something like:
-
- `(int []) { 2, 3 }'
-
- implies that the array has two elements. */
- if (TREE_CODE (type) == ARRAY_TYPE && !COMPLETE_TYPE_P (type))
- cp_complete_array_type (&TREE_TYPE (compound_literal),
- compound_literal, 1);
+ TREE_TYPE (compound_literal) = type;
+ /* Mark the expression as a compound literal. */
+ TREE_HAS_CONSTRUCTOR (compound_literal) = 1;
+ return compound_literal;
}
- TREE_HAS_CONSTRUCTOR (compound_literal) = 1;
- return compound_literal;
+ /* Create a temporary variable to represent the compound literal. */
+ var = create_temporary_var (type);
+ if (!current_function_decl)
+ {
+ /* If this compound-literal appears outside of a function, then
+ the corresponding variable has static storage duration, just
+ like the variable in whose initializer it appears. */
+ TREE_STATIC (var) = 1;
+ /* The variable has internal linkage, since there is no need to
+ reference it from another translation unit. */
+ TREE_PUBLIC (var) = 0;
+ /* It must have a name, so that the name mangler can mangle it. */
+ DECL_NAME (var) = make_anon_name ();
+ }
+ /* We must call pushdecl, since the gimplifier complains if the
+ variable has not been declared via a BIND_EXPR. */
+ pushdecl (var);
+ /* Initialize the variable as we would any other variable with a
+ brace-enclosed initializer. */
+ cp_finish_decl (var, compound_literal,
+ /*init_const_expr_p=*/false,
+ /*asmspec_tree=*/NULL_TREE,
+ LOOKUP_ONLYCONVERTING);
+ return var;
}
/* Return the declaration for the function-name variable indicated by
gcc_assert (DECL_TEMPLATE_PARMS (tmpl));
+ check_default_tmpl_args (decl, DECL_TEMPLATE_PARMS (tmpl),
+ /*is_primary=*/true, /*is_partial=*/false,
+ /*is_friend=*/0);
+
return finish_template_type_parm (aggr, tmpl);
}
&& TREE_CODE (argument) != UNBOUND_CLASS_TEMPLATE)
{
if (TREE_CODE (argument) == TYPE_DECL)
- {
- tree t = TREE_TYPE (argument);
-
- /* Try to emit a slightly smarter error message if we detect
- that the user is using a template instantiation. */
- if (CLASSTYPE_TEMPLATE_INFO (t)
- && CLASSTYPE_TEMPLATE_INSTANTIATION (t))
- error ("invalid use of type %qT as a default value for a "
- "template template-parameter", t);
- else
- error ("invalid use of %qD as a default value for a template "
- "template-parameter", argument);
- }
+ 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;
/* Begin a class definition, as indicated by T. */
tree
-begin_class_definition (tree t)
+begin_class_definition (tree t, tree attributes)
{
if (t == error_mark_node)
return error_mark_node;
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;
before. */
if (! TYPE_ANONYMOUS_P (t))
{
- struct c_fileinfo *finfo = get_fileinfo (lbasename (input_filename));
+ struct c_fileinfo *finfo = get_fileinfo (input_filename);
CLASSTYPE_INTERFACE_ONLY (t) = finfo->interface_only;
SET_CLASSTYPE_INTERFACE_UNKNOWN_X
(t, finfo->interface_unknown);
/* Mark the DECL as a member of the current class. */
DECL_CONTEXT (decl) = current_class_type;
+ /* Check for bare parameter packs in the member variable declaration. */
+ if (TREE_CODE (decl) == FIELD_DECL)
+ {
+ if (check_for_bare_parameter_packs (&TREE_TYPE (decl)))
+ TREE_TYPE (decl) = error_mark_node;
+ if (check_for_bare_parameter_packs (&DECL_ATTRIBUTES (decl)))
+ DECL_ATTRIBUTES (decl) = NULL_TREE;
+ }
+
/* [dcl.link]
A C language linkage is ignored for the names of class members
/* There's a good chance that we'll have to mangle names at some
point, even if only for emission in debugging information. */
- if (TREE_CODE (decl) == VAR_DECL
- || TREE_CODE (decl) == FUNCTION_DECL)
+ if ((TREE_CODE (decl) == VAR_DECL
+ || TREE_CODE (decl) == FUNCTION_DECL)
+ && !processing_template_decl)
mangle_decl (decl);
}
decl = lookup_template_class (name, args,
NULL_TREE, NULL_TREE, entering_scope,
- tf_error | tf_warning | tf_user);
+ tf_warning_or_error | tf_user);
if (decl != error_mark_node)
decl = TYPE_STUB_DECL (decl);
error ("%<::%D%> has not been declared", name);
}
+/* If FNS is a member function, a set of member functions, or a
+ template-id referring to one or more member functions, return a
+ BASELINK for FNS, incorporating the current access context.
+ Otherwise, return FNS unchanged. */
+
+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, /*optype=*/NULL_TREE);
+}
+
/* ID_EXPRESSION is a representation of parsed, but unprocessed,
id-expression. (See cp_parser_id_expression for details.) SCOPE,
if non-NULL, is the type or namespace used to explicitly qualify
{
*idk = CP_ID_KIND_NONE;
if (!processing_template_decl)
- return DECL_INITIAL (decl);
+ {
+ used_types_insert (TREE_TYPE (decl));
+ return DECL_INITIAL (decl);
+ }
return decl;
}
else
}
else if (is_overloaded_fn (decl))
{
- tree first_fn = OVL_CURRENT (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);
return finish_class_member_access_expr (decl, id_expression,
/*template_p=*/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)
+ && DECL_CLASS_SCOPE_P (decl))
{
- tree path;
-
- path = currently_open_derived_class (DECL_CONTEXT (decl));
- perform_or_defer_access_check (TYPE_BINFO (path), decl);
+ tree context = context_for_name_lookup (decl);
+ if (context != current_class_type)
+ {
+ tree path = currently_open_derived_class (context);
+ perform_or_defer_access_check (TYPE_BINFO (path),
+ decl, decl);
+ }
}
decl = convert_from_reference (decl);
{
type = make_aggr_type (TYPEOF_TYPE);
TYPEOF_TYPE_EXPR (type) = expr;
+ SET_TYPE_STRUCTURAL_EQUALITY (type);
return type;
}
- type = TREE_TYPE (expr);
+ type = unlowered_expr_type (expr);
if (!type || type == unknown_type_node)
{
return type;
}
+/* Perform C++-specific checks for __builtin_offsetof before calling
+ fold_offsetof. */
+
+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);
+}
+
/* Called from expand_body via walk_tree. Replace all AGGR_INIT_EXPRs
with equivalent CALL_EXPRs. */
tree aggr_init_expr = *tp;
/* Form an appropriate CALL_EXPR. */
- 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 fn = AGGR_INIT_EXPR_FN (aggr_init_expr);
+ tree slot = AGGR_INIT_EXPR_SLOT (aggr_init_expr);
tree type = TREE_TYPE (slot);
tree call_expr;
style = arg;
}
+ call_expr = build_call_array (TREE_TYPE (TREE_TYPE (TREE_TYPE (fn))),
+ fn,
+ aggr_init_expr_nargs (aggr_init_expr),
+ AGGR_INIT_EXPR_ARGP (aggr_init_expr));
+
if (style == ctor)
{
/* Replace the first argument to the ctor with the address of the
slot. */
- 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_ARG (call_expr, 0) =
+ build1 (ADDR_EXPR, build_pointer_type (type), slot);
}
-
- call_expr = build3 (CALL_EXPR,
- TREE_TYPE (TREE_TYPE (TREE_TYPE (fn))),
- fn, args, NULL_TREE);
-
- if (style == arg)
+ else if (style == arg)
{
/* Just mark it addressable here, and leave the rest to
expand_call{,_inline}. */
/* Emit all thunks to FN that should be emitted when FN is emitted. */
-static void
+void
emit_associated_thunks (tree fn)
{
/* When we use vcall offsets, we emit thunks with the virtual
/* Generate RTL for FN. */
void
-expand_body (tree fn)
-{
- tree saved_function;
-
- /* Compute the appropriate object-file linkage for inline
- functions. */
- if (DECL_DECLARED_INLINE_P (fn))
- import_export_decl (fn);
-
- /* If FN is external, then there's no point in generating RTL for
- it. This situation can arise with an inline function under
- `-fexternal-templates'; we instantiate the function, even though
- we're not planning on emitting it, in case we get a chance to
- inline it. */
- if (DECL_EXTERNAL (fn))
- return;
-
- /* ??? When is this needed? */
- saved_function = current_function_decl;
-
- /* Emit any thunks that should be emitted at the same time as FN. */
- emit_associated_thunks (fn);
-
- /* This function is only called from cgraph, or recursively from
- emit_associated_thunks. In neither case should we be currently
- generating trees for a function. */
- gcc_assert (function_depth == 0);
-
- tree_rest_of_compilation (fn);
-
- current_function_decl = saved_function;
-
- if (DECL_CLONED_FUNCTION_P (fn))
- {
- /* If this is a clone, go through the other clones now and mark
- their parameters used. We have to do that here, as we don't
- know whether any particular clone will be expanded, and
- therefore cannot pick one arbitrarily. */
- 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;
- }
- }
-}
-
-/* Generate RTL for FN. */
-
-void
expand_or_defer_fn (tree fn)
{
/* When the parser calls us after finishing the body of a template
}
/* Replace AGGR_INIT_EXPRs with appropriate CALL_EXPRs. */
- walk_tree_without_duplicates (&DECL_SAVED_TREE (fn),
- simplify_aggr_init_exprs_r,
- NULL);
+ cp_walk_tree_without_duplicates (&DECL_SAVED_TREE (fn),
+ simplify_aggr_init_exprs_r,
+ NULL);
/* If this is a constructor or destructor body, we have to clone
it. */
return;
}
- /* If this function is marked with the constructor attribute, add it
- to the list of functions to be called along with constructors
- from static duration objects. */
- if (DECL_STATIC_CONSTRUCTOR (fn))
- static_ctors = tree_cons (NULL_TREE, fn, static_ctors);
-
- /* If this function is marked with the destructor attribute, add it
- to the list of functions to be called along with destructors from
- static duration objects. */
- if (DECL_STATIC_DESTRUCTOR (fn))
- static_dtors = tree_cons (NULL_TREE, fn, static_dtors);
-
/* We make a decision about linkage for these functions at the end
of the compilation. Until that point, we do not want the back
end to output them -- but we do want it to see the bodies of
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);
+ cp_walk_tree (tp, finalize_nrv_r, &data, 0);
htab_delete (data.visited);
}
+\f
+/* For all elements of CLAUSES, validate them vs OpenMP constraints.
+ Remove any elements from the list that are invalid. */
+
+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 (!type_dependent_expression_p (t)
+ && !INTEGRAL_TYPE_P (TREE_TYPE (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 (!type_dependent_expression_p (t)
+ && !INTEGRAL_TYPE_P (TREE_TYPE (t)))
+ {
+ error ("schedule chunk size expression must be integral");
+ remove = true;
+ }
+ break;
-/* Perform initialization related to this module. */
+ 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;
+ }
+ }
+
+ /* We're interested in the base element, not arrays. */
+ inner_type = type = TREE_TYPE (t);
+ while (TREE_CODE (inner_type) == ARRAY_TYPE)
+ inner_type = TREE_TYPE (inner_type);
+
+ /* Check for special function availability by building a call to one.
+ Save the results, because later we won't be in the right context
+ for making these queries. */
+ 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;
+
+ /* Always allocate 3 elements for simplicity. These are the
+ function decls for the ctor, dtor, and assignment op.
+ This layout is known to the three lang hooks,
+ cxx_omp_clause_default_init, cxx_omp_clause_copy_init,
+ and cxx_omp_clause_assign_op. */
+ 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);
+
+ if (targetm.cxx.cdtor_returns_this ())
+ /* Because constructors and destructors return this,
+ the call will have been cast to "void". Remove the
+ cast here. We would like to use STRIP_NOPS, but it
+ wouldn't work here because TYPE_MODE (t) and
+ TYPE_MODE (TREE_OPERAND (t, 0)) are different.
+ They are VOIDmode and Pmode, respectively. */
+ if (TREE_CODE (t) == NOP_EXPR)
+ t = TREE_OPERAND (t, 0);
+
+ 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);
+
+ if (targetm.cxx.cdtor_returns_this ())
+ /* Because constructors and destructors return this,
+ the call will have been cast to "void". Remove the
+ cast here. We would like to use STRIP_NOPS, but it
+ wouldn't work here because TYPE_MODE (t) and
+ TYPE_MODE (TREE_OPERAND (t, 0)) are different.
+ They are VOIDmode and Pmode, respectively. */
+ if (TREE_CODE (t) == NOP_EXPR)
+ t = TREE_OPERAND (t, 0);
+
+ 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);
+
+ /* We'll have called convert_from_reference on the call, which
+ may well have added an indirect_ref. It's unneeded here,
+ and in the way, so kill it. */
+ 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;
+}
+
+/* For all variables in the tree_list VARS, mark them as thread local. */
+
+void
+finish_omp_threadprivate (tree vars)
+{
+ tree t;
+
+ /* Mark every variable in VARS to be assigned thread local storage. */
+ for (t = vars; t; t = TREE_CHAIN (t))
+ {
+ tree v = TREE_PURPOSE (t);
+
+ /* If V had already been marked threadprivate, it doesn't matter
+ whether it had been used prior to this point. */
+ 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
+ {
+ /* Allocate a LANG_SPECIFIC structure for V, if needed. */
+ if (DECL_LANG_SPECIFIC (v) == NULL)
+ {
+ retrofit_lang_decl (v);
+
+ /* Make sure that DECL_DISCRIMINATOR_P continues to be true
+ after the allocation of the lang_decl structure. */
+ 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 rtl has been already set for this var, call
+ make_decl_rtl once again, so that encode_section_info
+ has a chance to look at the new decl flags. */
+ if (DECL_RTL_SET_P (v))
+ make_decl_rtl (v);
+ }
+ CP_DECL_THREADPRIVATE_P (v) = 1;
+ }
+ }
+}
+
+/* Build an OpenMP structured block. */
+
+tree
+begin_omp_structured_block (void)
+{
+ return do_pushlevel (sk_omp);
+}
+
+tree
+finish_omp_structured_block (tree block)
+{
+ return do_poplevel (block);
+}
+
+/* Similarly, except force the retention of the 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);
+}
+
+/* Build and validate an OMP_FOR statement. CLAUSES, BODY, COND, INCR
+ are directly for their associated operands in the statement. DECL
+ and INIT are a combo; if DECL is NULL then INIT ought to be a
+ MODIFY_EXPR, and the DECL should be extracted. PRE_BODY are
+ optional statements that need to go before the loop into its
+ sk_omp scope. */
+
+tree
+finish_omp_for (location_t locus, tree decl, tree init, tree cond,
+ tree incr, tree body, tree pre_body)
+{
+ tree omp_for = NULL;
+
+ 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);
+
+ /* This is really just a place-holder. We'll be decomposing this
+ again and going through the build_modify_expr path below when
+ we instantiate the thing. */
+ 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;
+ }
+
+ if (!processing_template_decl)
+ init = fold_build_cleanup_point_expr (TREE_TYPE (init), init);
+ init = build_modify_expr (decl, NOP_EXPR, init);
+ if (cond && TREE_SIDE_EFFECTS (cond) && COMPARISON_CLASS_P (cond))
+ {
+ int n = TREE_SIDE_EFFECTS (TREE_OPERAND (cond, 1)) != 0;
+ tree t = TREE_OPERAND (cond, n);
+
+ if (!processing_template_decl)
+ TREE_OPERAND (cond, n)
+ = fold_build_cleanup_point_expr (TREE_TYPE (t), t);
+ }
+ if (decl != error_mark_node && init != error_mark_node)
+ omp_for = c_finish_omp_for (locus, decl, init, cond, incr, body, pre_body);
+ if (omp_for != NULL
+ && TREE_CODE (OMP_FOR_INCR (omp_for)) == MODIFY_EXPR
+ && TREE_SIDE_EFFECTS (TREE_OPERAND (OMP_FOR_INCR (omp_for), 1))
+ && BINARY_CLASS_P (TREE_OPERAND (OMP_FOR_INCR (omp_for), 1)))
+ {
+ tree t = TREE_OPERAND (OMP_FOR_INCR (omp_for), 1);
+ int n = TREE_SIDE_EFFECTS (TREE_OPERAND (t, 1)) != 0;
+
+ if (!processing_template_decl)
+ TREE_OPERAND (t, n)
+ = fold_build_cleanup_point_expr (TREE_TYPE (TREE_OPERAND (t, n)),
+ TREE_OPERAND (t, n));
+ }
+ return omp_for;
+}
+
+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;
+
+ /* Even in a template, we can detect invalid uses of the atomic
+ pragma if neither LHS nor RHS is type-dependent. */
+ 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, integer_zero_node,
+ build2 (code, void_type_node, orig_lhs, orig_rhs));
+ 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);
+}
+
+/* True if OpenMP sharing attribute of DECL is predetermined. */
+
+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;
+
+ /* Static data members are predetermined as shared. */
+ 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;
+}
+\f
+void
init_cp_semantics (void)
{
}
+\f
+/* Build a STATIC_ASSERT for a static assertion with the condition
+ CONDITION and the message text MESSAGE. LOCATION is the location
+ of the static assertion in the source code. When MEMBER_P, this
+ static assertion is a member of a class. */
+void
+finish_static_assert (tree condition, tree message, location_t location,
+ bool member_p)
+{
+ if (type_dependent_expression_p (condition)
+ || value_dependent_expression_p (condition))
+ {
+ /* We're in a template; build a STATIC_ASSERT and put it in
+ the right place. */
+ tree assertion;
+
+ assertion = make_node (STATIC_ASSERT);
+ STATIC_ASSERT_CONDITION (assertion) = condition;
+ STATIC_ASSERT_MESSAGE (assertion) = message;
+ STATIC_ASSERT_SOURCE_LOCATION (assertion) = location;
+
+ if (member_p)
+ maybe_add_class_template_decl_list (current_class_type,
+ assertion,
+ /*friend_p=*/0);
+ else
+ add_stmt (assertion);
+
+ return;
+ }
+
+ /* Fold the expression and convert it to a boolean value. */
+ condition = fold_non_dependent_expr (condition);
+ condition = cp_convert (boolean_type_node, condition);
+
+ if (TREE_CODE (condition) == INTEGER_CST && !integer_zerop (condition))
+ /* Do nothing; the condition is satisfied. */
+ ;
+ else
+ {
+ location_t saved_loc = input_location;
+
+ input_location = location;
+ if (TREE_CODE (condition) == INTEGER_CST
+ && integer_zerop (condition))
+ /* Report the error. */
+ error ("static assertion failed: %E", message);
+ else if (condition && condition != error_mark_node)
+ error ("non-constant condition for static assertion");
+ input_location = saved_loc;
+ }
+}
+\f
+/* Implements the C++0x decltype keyword. Returns the type of EXPR,
+ suitable for use as a type-specifier.
+
+ ID_EXPRESSION_OR_MEMBER_ACCESS_P is true when EXPR was parsed as an
+ id-expression or a class member access, FALSE when it was parsed as
+ a full expression. */
+tree
+finish_decltype_type (tree expr, bool id_expression_or_member_access_p)
+{
+ tree orig_expr = expr;
+ tree type;
+
+ if (!expr || error_operand_p (expr))
+ return error_mark_node;
+
+ if (TYPE_P (expr)
+ || TREE_CODE (expr) == TYPE_DECL
+ || (TREE_CODE (expr) == BIT_NOT_EXPR
+ && TYPE_P (TREE_OPERAND (expr, 0))))
+ {
+ error ("argument to decltype must be an expression");
+ return error_mark_node;
+ }
+
+ if (type_dependent_expression_p (expr))
+ {
+ type = make_aggr_type (DECLTYPE_TYPE);
+ DECLTYPE_TYPE_EXPR (type) = expr;
+ DECLTYPE_TYPE_ID_EXPR_OR_MEMBER_ACCESS_P (type)
+ = id_expression_or_member_access_p;
+ SET_TYPE_STRUCTURAL_EQUALITY (type);
+
+ return type;
+ }
+
+ /* The type denoted by decltype(e) is defined as follows: */
+
+ if (id_expression_or_member_access_p)
+ {
+ /* If e is an id-expression or a class member access (5.2.5
+ [expr.ref]), decltype(e) is defined as the type of the entity
+ named by e. If there is no such entity, or e names a set of
+ overloaded functions, the program is ill-formed. */
+ if (TREE_CODE (expr) == IDENTIFIER_NODE)
+ expr = lookup_name (expr);
+
+ if (TREE_CODE (expr) == INDIRECT_REF)
+ /* This can happen when the expression is, e.g., "a.b". Just
+ look at the underlying operand. */
+ expr = TREE_OPERAND (expr, 0);
+
+ if (TREE_CODE (expr) == OFFSET_REF
+ || TREE_CODE (expr) == MEMBER_REF)
+ /* We're only interested in the field itself. If it is a
+ BASELINK, we will need to see through it in the next
+ step. */
+ expr = TREE_OPERAND (expr, 1);
+
+ if (TREE_CODE (expr) == BASELINK)
+ /* See through BASELINK nodes to the underlying functions. */
+ expr = BASELINK_FUNCTIONS (expr);
+
+ if (TREE_CODE (expr) == OVERLOAD)
+ {
+ if (OVL_CHAIN (expr))
+ {
+ error ("%qE refers to a set of overloaded functions", orig_expr);
+ return error_mark_node;
+ }
+ else
+ /* An overload set containing only one function: just look
+ at that function. */
+ expr = OVL_FUNCTION (expr);
+ }
+
+ switch (TREE_CODE (expr))
+ {
+ case FIELD_DECL:
+ if (DECL_C_BIT_FIELD (expr))
+ {
+ type = DECL_BIT_FIELD_TYPE (expr);
+ break;
+ }
+ /* Fall through for fields that aren't bitfields. */
+
+ case FUNCTION_DECL:
+ case VAR_DECL:
+ case CONST_DECL:
+ case PARM_DECL:
+ case RESULT_DECL:
+ type = TREE_TYPE (expr);
+ break;
+
+ case ERROR_MARK:
+ type = error_mark_node;
+ break;
+
+ case COMPONENT_REF:
+ type = is_bitfield_expr_with_lowered_type (expr);
+ if (!type)
+ type = TREE_TYPE (TREE_OPERAND (expr, 1));
+ break;
+
+ case BIT_FIELD_REF:
+ gcc_unreachable ();
+
+ case INTEGER_CST:
+ /* We can get here when the id-expression refers to an
+ enumerator. */
+ type = TREE_TYPE (expr);
+ break;
+
+ default:
+ gcc_assert (TYPE_P (expr) || DECL_P (expr)
+ || TREE_CODE (expr) == SCOPE_REF);
+ error ("argument to decltype must be an expression");
+ return error_mark_node;
+ }
+ }
+ else
+ {
+ tree fndecl;
+
+ /* Expressions of reference type are sometimes wrapped in
+ INDIRECT_REFs. INDIRECT_REFs are just internal compiler
+ representation, not part of the language, so we have to look
+ through them. */
+ if (TREE_CODE (expr) == INDIRECT_REF
+ && TREE_CODE (TREE_TYPE (TREE_OPERAND (expr, 0)))
+ == REFERENCE_TYPE)
+ expr = TREE_OPERAND (expr, 0);
+
+ if (TREE_CODE (expr) == CALL_EXPR
+ && (fndecl = get_callee_fndecl (expr))
+ && (fndecl != error_mark_node))
+ /* If e is a function call (5.2.2 [expr.call]) or an
+ invocation of an overloaded operator (parentheses around e
+ are ignored), decltype(e) is defined as the return type of
+ that function. */
+ type = TREE_TYPE (TREE_TYPE (fndecl));
+ else
+ {
+ type = is_bitfield_expr_with_lowered_type (expr);
+ if (type)
+ {
+ /* Bitfields are special, because their type encodes the
+ number of bits they store. If the expression referenced a
+ bitfield, TYPE now has the declared type of that
+ bitfield. */
+ type = cp_build_qualified_type (type,
+ cp_type_quals (TREE_TYPE (expr)));
+
+ if (real_lvalue_p (expr))
+ type = build_reference_type (type);
+ }
+ else
+ {
+ /* Otherwise, where T is the type of e, if e is an lvalue,
+ decltype(e) is defined as T&, otherwise decltype(e) is
+ defined as T. */
+ type = TREE_TYPE (expr);
+ if (type == error_mark_node)
+ return error_mark_node;
+ else if (expr == current_class_ptr)
+ /* If the expression is just "this", we want the
+ cv-unqualified pointer for the "this" type. */
+ type = TYPE_MAIN_VARIANT (type);
+ else if (real_lvalue_p (expr))
+ {
+ if (TREE_CODE (type) != REFERENCE_TYPE)
+ type = build_reference_type (type);
+ }
+ else
+ type = non_reference (type);
+ }
+ }
+ }
+
+ if (!type || type == unknown_type_node)
+ {
+ error ("type of %qE is unknown", expr);
+ return error_mark_node;
+ }
+
+ return type;
+}
+
+/* Called from trait_expr_value to evaluate either __has_nothrow_assign or
+ __has_nothrow_copy, depending on assign_p. */
+
+static bool
+classtype_has_nothrow_assign_or_copy_p (tree type, bool assign_p)
+{
+ tree fns;
+
+ if (assign_p)
+ {
+ int ix;
+ ix = lookup_fnfields_1 (type, ansi_assopname (NOP_EXPR));
+ if (ix < 0)
+ return false;
+ fns = VEC_index (tree, CLASSTYPE_METHOD_VEC (type), ix);
+ }
+ else if (TYPE_HAS_INIT_REF (type))
+ {
+ /* If construction of the copy constructor was postponed, create
+ it now. */
+ if (CLASSTYPE_LAZY_COPY_CTOR (type))
+ lazily_declare_fn (sfk_copy_constructor, type);
+ fns = CLASSTYPE_CONSTRUCTORS (type);
+ }
+ else
+ return false;
+
+ for (; fns; fns = OVL_NEXT (fns))
+ if (!TREE_NOTHROW (OVL_CURRENT (fns)))
+ return false;
+
+ return true;
+}
+
+/* Actually evaluates the trait. */
+
+static bool
+trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
+{
+ enum tree_code type_code1;
+ tree t;
+
+ type_code1 = TREE_CODE (type1);
+
+ switch (kind)
+ {
+ case CPTK_HAS_NOTHROW_ASSIGN:
+ return (!CP_TYPE_CONST_P (type1) && type_code1 != REFERENCE_TYPE
+ && (trait_expr_value (CPTK_HAS_TRIVIAL_ASSIGN, type1, type2)
+ || (CLASS_TYPE_P (type1)
+ && classtype_has_nothrow_assign_or_copy_p (type1,
+ true))));
+
+ case CPTK_HAS_TRIVIAL_ASSIGN:
+ return (!CP_TYPE_CONST_P (type1) && type_code1 != REFERENCE_TYPE
+ && (pod_type_p (type1)
+ || (CLASS_TYPE_P (type1)
+ && TYPE_HAS_TRIVIAL_ASSIGN_REF (type1))));
+
+ case CPTK_HAS_NOTHROW_CONSTRUCTOR:
+ type1 = strip_array_types (type1);
+ return (trait_expr_value (CPTK_HAS_TRIVIAL_CONSTRUCTOR, type1, type2)
+ || (CLASS_TYPE_P (type1)
+ && (t = locate_ctor (type1, NULL)) && TREE_NOTHROW (t)));
+
+ case CPTK_HAS_TRIVIAL_CONSTRUCTOR:
+ type1 = strip_array_types (type1);
+ return (pod_type_p (type1)
+ || (CLASS_TYPE_P (type1) && TYPE_HAS_TRIVIAL_DFLT (type1)));
+
+ case CPTK_HAS_NOTHROW_COPY:
+ return (trait_expr_value (CPTK_HAS_TRIVIAL_COPY, type1, type2)
+ || (CLASS_TYPE_P (type1)
+ && classtype_has_nothrow_assign_or_copy_p (type1, false)));
+
+ case CPTK_HAS_TRIVIAL_COPY:
+ return (pod_type_p (type1) || type_code1 == REFERENCE_TYPE
+ || (CLASS_TYPE_P (type1) && TYPE_HAS_TRIVIAL_INIT_REF (type1)));
+
+ case CPTK_HAS_TRIVIAL_DESTRUCTOR:
+ type1 = strip_array_types (type1);
+ return (pod_type_p (type1)
+ || (CLASS_TYPE_P (type1)
+ && TYPE_HAS_TRIVIAL_DESTRUCTOR (type1)));
+
+ case CPTK_HAS_VIRTUAL_DESTRUCTOR:
+ return (CLASS_TYPE_P (type1)
+ && (t = locate_dtor (type1, NULL)) && DECL_VIRTUAL_P (t));
+
+ case CPTK_IS_ABSTRACT:
+ return (CLASS_TYPE_P (type1) && CLASSTYPE_PURE_VIRTUALS (type1));
+
+ case CPTK_IS_BASE_OF:
+ return (NON_UNION_CLASS_TYPE_P (type1) && NON_UNION_CLASS_TYPE_P (type2)
+ && DERIVED_FROM_P (type1, type2));
+
+ case CPTK_IS_CLASS:
+ return (NON_UNION_CLASS_TYPE_P (type1));
+
+ case CPTK_IS_CONVERTIBLE_TO:
+ /* TODO */
+ return false;
+
+ case CPTK_IS_EMPTY:
+ return (NON_UNION_CLASS_TYPE_P (type1) && CLASSTYPE_EMPTY_P (type1));
+
+ case CPTK_IS_ENUM:
+ return (type_code1 == ENUMERAL_TYPE);
+
+ case CPTK_IS_POD:
+ return (pod_type_p (type1));
+
+ case CPTK_IS_POLYMORPHIC:
+ return (CLASS_TYPE_P (type1) && TYPE_POLYMORPHIC_P (type1));
+
+ case CPTK_IS_UNION:
+ return (type_code1 == UNION_TYPE);
+
+ default:
+ gcc_unreachable ();
+ return false;
+ }
+}
+
+/* Process a trait expression. */
+
+tree
+finish_trait_expr (cp_trait_kind kind, tree type1, tree type2)
+{
+ gcc_assert (kind == CPTK_HAS_NOTHROW_ASSIGN
+ || kind == CPTK_HAS_NOTHROW_CONSTRUCTOR
+ || kind == CPTK_HAS_NOTHROW_COPY
+ || kind == CPTK_HAS_TRIVIAL_ASSIGN
+ || kind == CPTK_HAS_TRIVIAL_CONSTRUCTOR
+ || kind == CPTK_HAS_TRIVIAL_COPY
+ || kind == CPTK_HAS_TRIVIAL_DESTRUCTOR
+ || kind == CPTK_HAS_VIRTUAL_DESTRUCTOR
+ || kind == CPTK_IS_ABSTRACT
+ || kind == CPTK_IS_BASE_OF
+ || kind == CPTK_IS_CLASS
+ || kind == CPTK_IS_CONVERTIBLE_TO
+ || kind == CPTK_IS_EMPTY
+ || kind == CPTK_IS_ENUM
+ || kind == CPTK_IS_POD
+ || kind == CPTK_IS_POLYMORPHIC
+ || kind == CPTK_IS_UNION);
+
+ if (kind == CPTK_IS_CONVERTIBLE_TO)
+ {
+ sorry ("__is_convertible_to");
+ return error_mark_node;
+ }
+
+ if (type1 == error_mark_node
+ || ((kind == CPTK_IS_BASE_OF || kind == CPTK_IS_CONVERTIBLE_TO)
+ && type2 == error_mark_node))
+ return error_mark_node;
+
+ if (processing_template_decl)
+ {
+ tree trait_expr = make_node (TRAIT_EXPR);
+ TREE_TYPE (trait_expr) = boolean_type_node;
+ TRAIT_EXPR_TYPE1 (trait_expr) = type1;
+ TRAIT_EXPR_TYPE2 (trait_expr) = type2;
+ TRAIT_EXPR_KIND (trait_expr) = kind;
+ return trait_expr;
+ }
+
+ complete_type (type1);
+ if (type2)
+ complete_type (type2);
+
+ /* The only required diagnostic. */
+ if (kind == CPTK_IS_BASE_OF
+ && NON_UNION_CLASS_TYPE_P (type1) && NON_UNION_CLASS_TYPE_P (type2)
+ && !same_type_ignoring_top_level_qualifiers_p (type1, type2)
+ && !COMPLETE_TYPE_P (type2))
+ {
+ error ("incomplete type %qT not allowed", type2);
+ return error_mark_node;
+ }
+
+ return (trait_expr_value (kind, type1, type2)
+ ? boolean_true_node : boolean_false_node);
+}
#include "gt-cp-semantics.h"