/* Perform the semantic phase of parsing, i.e., the process of
building tree structure, checking semantic consistency, and
building RTL. These routines are used both during actual parsing
- and during the instantiation of template functions.
+ and during the instantiation of template functions.
Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
Free Software Foundation, Inc.
Written by Mark Mitchell (mmitchell@usa.net) based on code found
- formerly in parse.y and pt.c.
+ formerly in parse.y and pt.c.
This file is part of GCC.
under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
-
+
GCC is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
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, 59 Temple Place - Suite 330, Boston, MA
- 02111-1307, USA. */
+ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA. */
#include "config.h"
#include "system.h"
example:
class A {
- typedef int X;
+ typedef int X;
public:
- X f();
+ X f();
};
A::X A::f();
instantiations.
Typical use of access checking functions is described here:
-
+
1. When we enter a context that requires certain access checking
mode, the function `push_deferring_access_checks' is called with
DEFERRING argument specifying the desired mode. Access checking
names used in a decl-specifier-seq until we know what is being
declared because code like:
- class A {
- class B {};
- B* f();
+ class A {
+ class B {};
+ B* f();
}
A::B* A::f() { return 0; }
- is valid, even though `A::B' is not generally accessible.
+ 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;
-
+
/* The current mode of access checks. */
enum deferring_kind deferring_access_checks_kind;
-
+
} deferred_access;
-DEF_VEC_GC_O (deferred_access);
+DEF_VEC_O (deferred_access);
+DEF_VEC_ALLOC_O (deferred_access,gc);
/* Data for deferred access checking. */
-static GTY(()) VEC (deferred_access) *deferred_access_stack;
+static GTY(()) VEC(deferred_access,gc) *deferred_access_stack;
static GTY(()) unsigned deferred_access_no_check;
/* Save the current deferred access states and start deferred
{
deferred_access *ptr;
- ptr = VEC_safe_push (deferred_access, deferred_access_stack, NULL);
+ ptr = VEC_safe_push (deferred_access, gc, deferred_access_stack, NULL);
ptr->deferred_access_checks = NULL_TREE;
ptr->deferring_access_checks_kind = deferring;
}
VEC_pop (deferred_access, deferred_access_stack);
}
-/* Returns a TREE_LIST representing the deferred checks.
- The TREE_PURPOSE of each node is the type through which the
+/* Returns a TREE_LIST representing the deferred checks.
+ The TREE_PURPOSE of each node is the type through which the
access occurred; the TREE_VALUE is the declaration named.
*/
if (ptr->deferring_access_checks_kind == dk_no_deferred)
{
/* Check access. */
- for (; checks; checks = TREE_CHAIN (checks))
- enforce_access (TREE_PURPOSE (checks),
+ for (; checks; checks = TREE_CHAIN (checks))
+ enforce_access (TREE_PURPOSE (checks),
TREE_VALUE (checks));
}
else
/* Merge with parent. */
tree next;
tree original = ptr->deferred_access_checks;
-
+
for (; checks; checks = next)
{
tree probe;
-
+
next = TREE_CHAIN (checks);
for (probe = original; probe; probe = TREE_CHAIN (probe))
{
tree deferred_check;
- for (deferred_check = (VEC_last (deferred_access, deferred_access_stack)
- ->deferred_access_checks);
+ for (deferred_check = get_deferred_access_checks ();
deferred_check;
deferred_check = TREE_CHAIN (deferred_check))
/* Check access. */
- enforce_access (TREE_PURPOSE (deferred_check),
+ enforce_access (TREE_PURPOSE (deferred_check),
TREE_VALUE (deferred_check));
}
*/
if (deferred_access_no_check)
return;
-
+
gcc_assert (TREE_CODE (binfo) == TREE_BINFO);
ptr = VEC_last (deferred_access, deferred_access_stack);
-
+
/* 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);
return;
}
-
+
/* See if we are already going to perform this check. */
for (check = ptr->deferred_access_checks;
check;
return current_stmt_tree ()->stmts_are_full_exprs_p;
}
+/* T is a statement. Add it to the statement-tree. This is the C++
+ version. The C/ObjC frontends have a slightly different version of
+ this function. */
+
+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);
+
+ /* When we expand a statement-tree, we must know whether or not the
+ statements are full-expressions. We record that fact here. */
+ STMT_IS_FULL_EXPR_P (t) = stmts_are_full_exprs_p ();
+ }
+
+ /* Add T to the statement-tree. Non-side-effect statements need to be
+ recorded during statement expressions. */
+ append_to_statement_list_force (t, &cur_stmt_list);
+
+ return t;
+}
+
/* Returns the stmt_tree (if any) to which statements are currently
being added. If there is no active statement-tree, NULL is
returned. */
stmt_tree
current_stmt_tree (void)
{
- return (cfun
- ? &cfun->language->base.x_stmt_tree
+ return (cfun
+ ? &cfun->language->base.x_stmt_tree
: &scope_chain->x_stmt_tree);
}
/* Finish a scope. */
-static tree
+tree
do_poplevel (tree stmt_list)
{
tree block = NULL;
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;
}
-/* Begin a new scope. */
+/* Begin a new scope. */
static tree
do_pushlevel (scope_kind sk)
/* If *COND_P specifies a conditional with a declaration, transform the
loop such that
- while (A x = 42) { }
- for (; A x = 42;) { }
+ while (A x = 42) { }
+ for (; A x = 42;) { }
becomes
- while (true) { A x = 42; if (!x) break; }
- for (;;) { A x = 42; if (!x) break; }
+ while (true) { A x = 42; if (!x) break; }
+ for (;;) { A x = 42; if (!x) break; }
The statement list for BODY will be empty if the conditional did
not declare anything. */
-
+
static void
simplify_loop_decl_cond (tree *cond_p, tree body)
{
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);
addresses, or some such. */
DECL_UNINLINABLE (current_function_decl) = 1;
}
-
+
check_goto (destination);
return add_stmt (build_stmt (GOTO_EXPR, destination));
/* Process the COND of an if-statement, which may be given by
IF_STMT. */
-void
+void
finish_if_stmt_cond (tree cond, tree if_stmt)
{
finish_cond (&IF_COND (if_stmt), maybe_convert_cond (cond));
/* Finish an if-statement. */
-void
+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));
}
/* Begin a while-statement. Returns a newly created WHILE_STMT if
/* Process the COND of a while-statement, which may be given by
WHILE_STMT. */
-void
+void
finish_while_stmt_cond (tree cond, tree while_stmt)
{
finish_cond (&WHILE_COND (while_stmt), maybe_convert_cond (cond));
/* Finish a while-statement, which may be given by WHILE_STMT. */
-void
+void
finish_while_stmt (tree while_stmt)
{
WHILE_BODY (while_stmt) = do_poplevel (WHILE_BODY (while_stmt));
finish_return_stmt (tree expr)
{
tree r;
+ bool no_warning;
- expr = check_return_expr (expr);
+ expr = check_return_expr (expr, &no_warning);
if (!processing_template_decl)
{
if (DECL_DESTRUCTOR_P (current_function_decl)
- || (DECL_CONSTRUCTOR_P (current_function_decl)
+ || (DECL_CONSTRUCTOR_P (current_function_decl)
&& targetm.cxx.cdtor_returns_this ()))
{
/* Similarly, all destructors must run destructors for
}
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 ();
{
tree r;
- r = build_stmt (FOR_STMT, NULL_TREE, NULL_TREE,
+ r = build_stmt (FOR_STMT, NULL_TREE, NULL_TREE,
NULL_TREE, NULL_TREE);
if (flag_new_for_scope > 0)
if (!processing_template_decl)
{
if (warn_sequence_point)
- verify_sequence_points (expr);
+ verify_sequence_points (expr);
expr = convert_to_void (expr, "3rd expression in for");
}
else if (!type_dependent_expression_p (expr))
add_stmt (do_poplevel (scope));
}
- finish_stmt ();
+ finish_stmt ();
}
/* Finish a break-statement. */
tree
finish_break_stmt (void)
{
- return add_stmt (build_break_stmt ());
+ return add_stmt (build_stmt (BREAK_STMT));
}
/* Finish a continue-statement. */
tree
finish_continue_stmt (void)
{
- return add_stmt (build_continue_stmt ());
+ return add_stmt (build_stmt (CONTINUE_STMT));
}
/* Begin a switch-statement. Returns a new SWITCH_STMT if
SWITCH_STMT_BODY (switch_stmt) =
pop_stmt_list (SWITCH_STMT_BODY (switch_stmt));
- pop_switch ();
+ pop_switch ();
finish_stmt ();
scope = TREE_CHAIN (switch_stmt);
/* Begin a compound statement. FLAGS contains some bits that control the
behavior and context. If BCS_NO_SCOPE is set, the compound statement
does not define a scope. If BCS_FN_BODY is set, this is the outermost
- block of a function. If BCS_TRY_BLOCK is set, this is the block
+ block of a function. If BCS_TRY_BLOCK is set, this is the block
created on behalf of a TRY statement. Returns a token to be passed to
finish_compound_stmt. */
/* Normally, we try hard to keep the BLOCK for a statement-expression.
But, if it's a statement-expression with a scopeless block, there's
nothing to keep, and we don't want to accidentally keep a block
- *inside* the scopeless block. */
+ *inside* the scopeless block. */
keep_next_level (false);
}
else
{
tree r;
tree t;
+ int ninputs = list_length (input_operands);
+ int noutputs = list_length (output_operands);
if (!processing_template_decl)
{
- int ninputs, noutputs;
const char *constraint;
const char **oconstraints;
bool allows_mem, allows_reg, is_inout;
tree operand;
int i;
- ninputs = list_length (input_operands);
- noutputs = list_length (output_operands);
oconstraints = (const char **) alloca (noutputs * sizeof (char *));
string = resolve_asm_operand_names (string, output_operands,
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))
+ /* 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);
+
constraint = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (t)));
oconstraints[i] = constraint;
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));
+ operand = decay_conversion (TREE_VALUE (t));
/* If the type of the operand hasn't been determined (e.g.,
because it involves an overloaded function), then issue
resolve the overloading. */
if (TREE_TYPE (operand) == unknown_type_node)
{
- error ("type of asm operand %qE could not be determined",
- TREE_VALUE (t));
+ error ("type of asm operand %qE could not be determined",
+ TREE_VALUE (t));
operand = error_mark_node;
}
r = build_stmt (ASM_EXPR, string,
output_operands, input_operands,
clobbers);
- ASM_VOLATILE_P (r) = volatile_p;
+ ASM_VOLATILE_P (r) = volatile_p || noutputs == 0;
r = maybe_cleanup_point_expr_void (r);
return add_stmt (r);
}
/* When DECL goes out of scope, make sure that CLEANUP is executed. */
-void
+void
finish_decl_cleanup (tree decl, tree cleanup)
{
push_cleanup (decl, cleanup, false);
/* [expr.unary.op]/3 The qualified id of a pointer-to-member must not be
enclosed in parentheses. */
PTRMEM_OK_P (expr) = 0;
-
+
if (TREE_CODE (expr) == STRING_CST)
PAREN_STRING_LITERAL_P (expr) = 1;
-
+
return expr;
}
if (!object)
{
- if (current_function_decl
+ if (current_function_decl
&& DECL_STATIC_FUNCTION_P (current_function_decl))
- cp_error_at ("invalid use of member %qD in static member function",
- decl);
+ error ("invalid use of member %q+D in static member function", decl);
else
- cp_error_at ("invalid use of non-static data member %qD", decl);
+ error ("invalid use of non-static data member %q+D", decl);
error ("from this location");
return error_mark_node;
{
/* Set the cv qualifiers. */
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);
if (!access_type)
{
- cp_error_at ("object missing in reference to %qD", decl);
+ error ("object missing in reference to %q+D", decl);
error ("from this location");
return error_mark_node;
}
QUALIFYING_SCOPE is also non-null. Wrap this in a SCOPE_REF
for now. */
if (processing_template_decl)
- return build_min (SCOPE_REF, TREE_TYPE (decl),
- qualifying_scope, DECL_NAME (decl));
+ return build_qualified_name (TREE_TYPE (decl),
+ qualifying_scope,
+ DECL_NAME (decl),
+ /*template_p=*/false);
perform_or_defer_access_check (TYPE_BINFO (access_type), decl);
`A::B' then NESTED_NAME_SPECIFIER is `A'. */
void
-check_accessibility_of_qualified_id (tree decl,
- tree object_type,
+check_accessibility_of_qualified_id (tree decl,
+ tree object_type,
tree nested_name_specifier)
{
tree scope;
/* If we're not checking, return immediately. */
if (deferred_access_no_check)
return;
-
+
/* Determine the SCOPE of DECL. */
scope = context_for_name_lookup (decl);
/* If the SCOPE is not a type, then DECL is not a member. */
if (!TYPE_P (scope))
return;
/* Compute the scope through which DECL is being accessed. */
- if (object_type
+ if (object_type
/* OBJECT_TYPE might not be a class type; consider:
class A { typedef int I; };
I *p;
p->A::I::~I();
- In this case, we will have "A::I" as the DECL, but "I" as the
+ In this case, we will have "A::I" as the DECL, but "I" as the
OBJECT_TYPE. */
&& CLASS_TYPE_P (object_type)
&& DERIVED_FROM_P (scope, object_type))
class named to the left of the "::" operator. DONE is true if this
expression is a complete postfix-expression; it is false if this
expression is followed by '->', '[', '(', etc. ADDRESS_P is true
- iff this expression is the operand of '&'. */
+ iff this expression is the operand of '&'. TEMPLATE_P is true iff
+ the qualified-id was of the form "A::template B". TEMPLATE_ARG_P
+ is true iff this qualified name appears as a template argument. */
tree
-finish_qualified_id_expr (tree qualifying_class, tree expr, bool done,
- bool address_p)
+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 EXPR occurs as the operand of '&', use special handling that
permits a pointer-to-member. */
if (address_p && done)
{
if (TREE_CODE (expr) == SCOPE_REF)
expr = TREE_OPERAND (expr, 1);
- expr = build_offset_ref (qualifying_class, expr,
+ expr = build_offset_ref (qualifying_class, expr,
/*address_p=*/true);
return expr;
}
- if (TREE_CODE (expr) == FIELD_DECL)
+ /* Within the scope of a class, turn references to non-static
+ members into expression of the form "this->...". */
+ if (template_arg_p)
+ /* But, within a template argument, we do not want make the
+ transformation, as there is no "this" pointer. */
+ ;
+ 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)
/* If so, the expression may be relative to the current
class. */
if (!shared_member_p (fns)
- && current_class_type
+ && current_class_type
&& DERIVED_FROM_P (qualifying_class, current_class_type))
- expr = (build_class_member_access_expr
+ expr = (build_class_member_access_expr
(maybe_dummy_object (qualifying_class, NULL),
expr,
BASELINK_ACCESS_BINFO (expr),
/* Begin a statement-expression. The value returned must be passed to
finish_stmt_expr. */
-tree
+tree
begin_stmt_expr (void)
{
return push_stmt_list ();
}
/* Process the final expression of a statement expression. EXPR can be
- NULL, if the final expression is empty. Build up a TARGET_EXPR so
- that the result value can be safely returned to the enclosing
- expression. */
+ NULL, if the final expression is empty. Return a STATEMENT_LIST
+ containing all the statements in the statement-expression, or
+ ERROR_MARK_NODE if there was an error. */
tree
finish_stmt_expr_expr (tree expr, tree stmt_expr)
{
- tree result = NULL_TREE;
+ if (error_operand_p (expr))
+ 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. */
if (expr)
{
- if (!processing_template_decl && !VOID_TYPE_P (TREE_TYPE (expr)))
+ tree type;
+ type = TREE_TYPE (expr);
+ if (!dependent_type_p (type) && !VOID_TYPE_P (type))
{
- tree type = TREE_TYPE (expr);
-
- if (TREE_CODE (type) == ARRAY_TYPE
- || TREE_CODE (type) == FUNCTION_TYPE)
- expr = decay_conversion (expr);
-
- expr = require_complete_type (expr);
-
+ expr = decay_conversion (expr);
+ if (error_operand_p (expr))
+ return error_mark_node;
type = TREE_TYPE (expr);
-
- /* Build a TARGET_EXPR for this aggregate. finish_stmt_expr
- will then pull it apart so the lifetime of the target is
- within the scope of the expression containing this statement
- expression. */
- if (TREE_CODE (expr) == TARGET_EXPR)
- ;
- else if (!IS_AGGR_TYPE (type) || TYPE_HAS_TRIVIAL_INIT_REF (type))
- expr = build_target_expr_with_type (expr, type);
+ }
+ /* 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
{
- /* Copy construct. */
- expr = build_special_member_call
- (NULL_TREE, complete_ctor_identifier,
- build_tree_list (NULL_TREE, expr),
- type, LOOKUP_NORMAL);
- expr = build_cplus_new (type, expr);
- gcc_assert (TREE_CODE (expr) == TARGET_EXPR);
+ /* 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);
}
- }
-
- if (expr != error_mark_node)
- {
- result = build_stmt (EXPR_STMT, expr);
- EXPR_STMT_STMT_EXPR_RESULT (result) = 1;
- add_stmt (result);
+ 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;
}
}
-
- finish_stmt ();
- /* Remember the last expression so that finish_stmt_expr
- can pull it apart. */
- TREE_TYPE (stmt_expr) = result;
-
- return result;
+ /* 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;
}
/* Finish a statement-expression. EXPR should be the value returned
by the previous begin_stmt_expr. Returns an expression
representing the statement-expression. */
-tree
+tree
finish_stmt_expr (tree stmt_expr, bool has_no_scope)
{
- tree result, result_stmt, type;
- tree *result_stmt_p = NULL;
+ tree type;
+ tree result;
- result_stmt = TREE_TYPE (stmt_expr);
- TREE_TYPE (stmt_expr) = void_type_node;
- result = pop_stmt_list (stmt_expr);
+ if (error_operand_p (stmt_expr))
+ return error_mark_node;
- if (!result_stmt || VOID_TYPE_P (result_stmt))
- type = void_type_node;
- else
- {
- /* We need to search the statement expression for the result_stmt,
- since we'll need to replace it entirely. */
- tree t;
- result_stmt_p = &result;
- while (1)
- {
- t = *result_stmt_p;
- if (t == result_stmt)
- break;
+ gcc_assert (TREE_CODE (stmt_expr) == STATEMENT_LIST);
- switch (TREE_CODE (t))
- {
- case STATEMENT_LIST:
- {
- tree_stmt_iterator i = tsi_last (t);
- result_stmt_p = tsi_stmt_ptr (i);
- break;
- }
- case BIND_EXPR:
- result_stmt_p = &BIND_EXPR_BODY (t);
- break;
- case TRY_FINALLY_EXPR:
- case TRY_CATCH_EXPR:
- case CLEANUP_STMT:
- result_stmt_p = &TREE_OPERAND (t, 0);
- break;
- default:
- gcc_unreachable ();
- }
- }
- type = TREE_TYPE (EXPR_STMT_EXPR (result_stmt));
- }
+ type = TREE_TYPE (stmt_expr);
+ result = pop_stmt_list (stmt_expr);
if (processing_template_decl)
{
TREE_SIDE_EFFECTS (result) = 1;
STMT_EXPR_NO_SCOPE (result) = has_no_scope;
}
- else if (!VOID_TYPE_P (type))
+ else if (!TYPE_P (type))
{
- /* Pull out the TARGET_EXPR that is the final expression. Put
- the target's init_expr as the final expression and then put
- the statement expression itself as the target's init
- expr. Finally, return the target expression. */
- tree init, target_expr = EXPR_STMT_EXPR (result_stmt);
- gcc_assert (TREE_CODE (target_expr) == TARGET_EXPR);
-
- /* The initializer will be void if the initialization is done by
- AGGR_INIT_EXPR; propagate that out to the statement-expression as
- a whole. */
- init = TREE_OPERAND (target_expr, 1);
- type = TREE_TYPE (init);
-
- init = maybe_cleanup_point_expr (init);
- *result_stmt_p = init;
-
- if (VOID_TYPE_P (type))
- /* No frobbing needed. */;
- else if (TREE_CODE (result) == BIND_EXPR)
- {
- /* The BIND_EXPR created in finish_compound_stmt is void; if we're
- returning a value directly, give it the appropriate type. */
- if (VOID_TYPE_P (TREE_TYPE (result)))
- TREE_TYPE (result) = type;
- else
- gcc_assert (same_type_p (TREE_TYPE (result), type));
- }
- else if (TREE_CODE (result) == STATEMENT_LIST)
- /* We need to wrap a STATEMENT_LIST in a BIND_EXPR so it can have a
- type other than void. FIXME why can't we just return a value
- from STATEMENT_LIST? */
- result = build3 (BIND_EXPR, type, NULL, result, NULL);
-
- TREE_OPERAND (target_expr, 1) = result;
- result = target_expr;
+ gcc_assert (TREE_CODE (type) == TARGET_EXPR);
+ TARGET_EXPR_INITIAL (type) = result;
+ TREE_TYPE (result) = void_type_node;
+ result = type;
}
return result;
/* The unqualified name could not be resolved. */
fn = unqualified_fn_lookup_error (identifier);
}
- else
- fn = identifier;
return fn;
}
Returns code for the call. */
-tree
+tree
finish_call_expr (tree fn, tree args, bool disallow_virtual, bool koenig_p)
{
tree result;
function call is transformed into a qualified function call
using (*this) as the postfix-expression to the left of the
. operator.... [Otherwise] a contrived object of type T
- becomes the implied object argument.
+ becomes the implied object argument.
- This paragraph is unclear about this situation:
+ This paragraph is unclear about this situation:
struct A { void f(); };
struct B : public A {};
struct C : public A { void g() { B::f(); }};
In particular, for `B::f', this paragraph does not make clear
- whether "the class of that member function" refers to `A' or
+ whether "the class of that member function" refers to `A' or
to `B'. We believe it refers to `B'. */
- if (current_class_type
+ if (current_class_type
&& DERIVED_FROM_P (BINFO_TYPE (BASELINK_ACCESS_BINFO (fn)),
current_class_type)
&& current_class_ref)
}
result = build_new_method_call (object, fn, args, NULL_TREE,
- (disallow_virtual
+ (disallow_virtual
? LOOKUP_NONVIRTUAL : 0));
}
else if (is_overloaded_fn (fn))
- /* A call to a namespace-scope function. */
- result = build_new_function_call (fn, args);
+ {
+ /* If the function is an overloaded builtin, resolve it. */
+ 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)
+ /* A call to a namespace-scope function. */
+ result = build_new_function_call (fn, args, koenig_p);
+ }
else if (TREE_CODE (fn) == PSEUDO_DTOR_EXPR)
{
if (args)
have an overloaded `operator ()'. */
result = build_new_op (CALL_EXPR, LOOKUP_NORMAL, fn, args, NULL_TREE,
/*overloaded_p=*/NULL);
+
if (!result)
/* A call where the function is unknown. */
result = build_function_call (fn, args);
is indicated by CODE, which should be POSTINCREMENT_EXPR or
POSTDECREMENT_EXPR.) */
-tree
+tree
finish_increment_expr (tree expr, enum tree_code code)
{
- return build_x_unary_op (code, expr);
+ return build_x_unary_op (code, expr);
}
/* Finish a use of `this'. Returns an expression for `this'. */
-tree
+tree
finish_this_expr (void)
{
tree result;
the TYPE for the type given. If SCOPE is non-NULL, the expression
was of the form `OBJECT.SCOPE::~DESTRUCTOR'. */
-tree
+tree
finish_pseudo_destructor_expr (tree object, tree scope, tree destructor)
{
if (destructor == error_mark_node)
error ("invalid qualifying scope in pseudo-destructor name");
return error_mark_node;
}
-
+
/* [expr.pseudo] says both:
- The type designated by the pseudo-destructor-name shall be
+ The type designated by the pseudo-destructor-name shall be
the same as the object type.
- and:
+ and:
- The cv-unqualified versions of the object type and of the
+ The cv-unqualified versions of the object type and of the
type designated by the pseudo-destructor-name shall be the
same type.
- We implement the more generous second sentence, since that is
- what most other compilers do. */
- if (!same_type_ignoring_top_level_qualifiers_p (TREE_TYPE (object),
+ We implement the more generous second sentence, since that is
+ what most other compilers do. */
+ if (!same_type_ignoring_top_level_qualifiers_p (TREE_TYPE (object),
destructor))
{
error ("%qE is not of type %qT", object, destructor);
the INITIALIZER_LIST is being cast. */
tree
-finish_compound_literal (tree type, tree initializer_list)
+finish_compound_literal (tree type, VEC(constructor_elt,gc) *initializer_list)
{
tree compound_literal;
/* Build a CONSTRUCTOR for the INITIALIZER_LIST. */
compound_literal = build_constructor (NULL_TREE, initializer_list);
- /* Mark it as a compound-literal. */
- TREE_HAS_CONSTRUCTOR (compound_literal) = 1;
if (processing_template_decl)
TREE_TYPE (compound_literal) = type;
else
{
/* Check the initialization. */
- compound_literal = digest_init (type, compound_literal, NULL);
+ compound_literal = reshape_init (type, compound_literal);
+ 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:
implies that the array has two elements. */
if (TREE_CODE (type) == ARRAY_TYPE && !COMPLETE_TYPE_P (type))
- complete_array_type (type, compound_literal, 1);
+ cp_complete_array_type (&TREE_TYPE (compound_literal),
+ compound_literal, 1);
}
+ /* Mark it as a compound-literal. */
+ TREE_HAS_CONSTRUCTOR (compound_literal) = 1;
+
return compound_literal;
}
finish_fname (tree id)
{
tree decl;
-
+
decl = fname_decl (C_RID_CODE (id), id);
if (processing_template_decl)
decl = DECL_NAME (decl);
/* Finish a translation unit. */
-void
+void
finish_translation_unit (void)
{
/* In case there were missing closebraces,
/* Finish a template type parameter, specified as AGGR IDENTIFIER.
Returns the parameter. */
-tree
+tree
finish_template_type_parm (tree aggr, tree identifier)
{
if (aggr != class_type_node)
/* Finish a template template parameter, specified as AGGR IDENTIFIER.
Returns the parameter. */
-tree
+tree
finish_template_template_parm (tree aggr, tree identifier)
{
tree decl = build_decl (TYPE_DECL, identifier, NULL_TREE);
/* Try to emit a slightly smarter error message if we detect
that the user is using a template instantiation. */
- if (CLASSTYPE_TEMPLATE_INFO (t)
+ 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);
+ "template template-parameter", t);
else
error ("invalid use of %qD as a default value for a template "
- "template-parameter", argument);
+ "template-parameter", argument);
}
else
error ("invalid default argument for a template template parameter");
/* A non-implicit typename comes from code like:
template <typename T> struct A {
- template <typename U> struct A<T>::B ...
+ template <typename U> struct A<T>::B ...
This is erroneous. */
else if (TREE_CODE (t) == TYPENAME_TYPE)
if (t == error_mark_node || ! IS_AGGR_TYPE (t))
{
t = make_aggr_type (RECORD_TYPE);
- pushtag (make_anon_name (), t, 0);
- }
-
- /* If this type was already complete, and we see another definition,
- that's an error. */
- if (COMPLETE_TYPE_P (t))
- {
- error ("redefinition of %q#T", t);
- cp_error_at ("previous definition of %q#T", t);
- return error_mark_node;
+ pushtag (make_anon_name (), t, /*tag_scope=*/ts_current);
}
/* Update the location of the decl. */
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, 0);
+ pushtag (TYPE_IDENTIFIER (t), t, /*tag_scope=*/ts_current);
}
maybe_process_partial_specialization (t);
pushclass (t);
(t, finfo->interface_unknown);
}
reset_specialization();
-
+
/* Make a declaration for this class in its own scope. */
build_self_reference ();
gcc_assert (TREE_CHAIN (decl) == NULL_TREE);
/* Set up access control for DECL. */
- TREE_PRIVATE (decl)
+ TREE_PRIVATE (decl)
= (current_access_specifier == access_private_node);
- TREE_PROTECTED (decl)
+ TREE_PROTECTED (decl)
= (current_access_specifier == access_protected_node);
if (TREE_CODE (decl) == TEMPLATE_DECL)
{
/* Put functions on the TYPE_METHODS list and everything else on the
TYPE_FIELDS list. Note that these are built up in reverse order.
We reverse them (to obtain declaration order) in finish_struct. */
- if (TREE_CODE (decl) == FUNCTION_DECL
+ if (TREE_CODE (decl) == FUNCTION_DECL
|| DECL_FUNCTION_TEMPLATE_P (decl))
{
/* We also need to add this function to the
CLASSTYPE_METHOD_VEC. */
- add_method (current_class_type, decl);
-
- TREE_CHAIN (decl) = TYPE_METHODS (current_class_type);
- TYPE_METHODS (current_class_type) = 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,
- /*friend_p=*/0);
+ maybe_add_class_template_decl_list (current_class_type, decl,
+ /*friend_p=*/0);
+ }
}
/* Enter the DECL into the scope of the class. */
- else if ((TREE_CODE (decl) == USING_DECL && TREE_TYPE (decl))
+ else if ((TREE_CODE (decl) == USING_DECL && !DECL_DEPENDENT_P (decl))
|| pushdecl_class_level (decl))
{
/* All TYPE_DECLs go at the end of TYPE_FIELDS. Ordinary fields
list.) */
if (TREE_CODE (decl) == TYPE_DECL)
- TYPE_FIELDS (current_class_type)
+ TYPE_FIELDS (current_class_type)
= chainon (TYPE_FIELDS (current_class_type), decl);
else
{
TYPE_FIELDS (current_class_type) = decl;
}
- maybe_add_class_template_decl_list (current_class_type, decl,
+ maybe_add_class_template_decl_list (current_class_type, decl,
/*friend_p=*/0);
}
{
gcc_assert (pch_file);
- /* A non-template inline function with external linkage will always
- be COMDAT. As we must eventually determine the linkage of all
- functions, and as that causes writes to the data mapped in from
- the PCH file, it's advantageous to mark the functions at this
- point. */
- if (TREE_CODE (decl) == FUNCTION_DECL
- && TREE_PUBLIC (decl)
- && DECL_DECLARED_INLINE_P (decl)
- && !DECL_IMPLICIT_INSTANTIATION (decl))
- {
- comdat_linkage (decl);
- DECL_INTERFACE_KNOWN (decl) = 1;
- }
-
/* 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
access_{default,public,protected_private}_node. For a virtual base
we set TREE_TYPE. */
-tree
+tree
finish_base_specifier (tree base, tree access, bool virtual_p)
{
tree result;
else
{
if (cp_type_quals (base) != 0)
- {
- error ("base class %qT has cv qualifiers", base);
- base = TYPE_MAIN_VARIANT (base);
- }
+ {
+ 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;
void
qualified_name_lookup_error (tree scope, tree name, tree decl)
{
- if (TYPE_P (scope))
+ if (scope == error_mark_node)
+ ; /* We already complained. */
+ else if (TYPE_P (scope))
{
if (!COMPLETE_TYPE_P (scope))
error ("incomplete type %qT used in nested name specifier", scope);
else
error ("%<::%D%> has not been declared", name);
}
-
+
/* 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
ID_EXPRESSION. DECL is the entity to which that name has been
- resolved.
+ resolved.
*CONSTANT_EXPRESSION_P is true if we are presently parsing a
constant-expression. In that case, *NON_CONSTANT_EXPRESSION_P will
constant-expression, but a non-constant expression is also
permissible.
+ DONE is true if this expression is a complete postfix-expression;
+ it is false if this expression is followed by '->', '[', '(', etc.
+ ADDRESS_P is true iff this expression is the operand of '&'.
+ TEMPLATE_P is true iff the qualified-id was of the form
+ "A::template B". TEMPLATE_ARG_P is true iff this qualified name
+ appears as a template argument.
+
If an error occurs, and it is the kind of error that might cause
the parser to abort a tentative parse, *ERROR_MSG is filled in. It
is the caller's responsibility to issue the message. *ERROR_MSG
Return an expression for the entity, after issuing appropriate
diagnostics. This function is also responsible for transforming a
reference to a non-static member into a COMPONENT_REF that makes
- the use of "this" explicit.
+ the use of "this" explicit.
Upon return, *IDK will be filled in appropriately. */
tree
-finish_id_expression (tree id_expression,
+finish_id_expression (tree id_expression,
tree decl,
tree scope,
cp_id_kind *idk,
- tree *qualifying_class,
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)
{
/* Initialize the output parameters. */
|| TREE_CODE (decl) == TYPE_DECL)
;
/* Look up the name. */
- else
+ else
{
if (decl == error_mark_node)
{
/* Name lookup failed. */
- if (scope
- && (!TYPE_P (scope)
+ if (scope
+ && (!TYPE_P (scope)
|| (!dependent_type_p (scope)
&& !(TREE_CODE (id_expression) == IDENTIFIER_NODE
&& IDENTIFIER_TYPENAME_P (id_expression)
was entirely defined. */
if (!scope && decl != error_mark_node)
maybe_note_name_used_in_class (id_expression, decl);
+
+ /* Disallow uses of local variables from containing functions. */
+ 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 we didn't find anything, or what we found was a type,
|| 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
+
+ if (integral_constant_expression_p
&& !dependent_type_p (TREE_TYPE (decl))
&& !(INTEGRAL_OR_ENUMERATION_TYPE_P (TREE_TYPE (r))))
{
}
return r;
}
- /* Similarly, we resolve enumeration constants to their
+ /* Similarly, we resolve enumeration constants to their
underlying values. */
else if (TREE_CODE (decl) == CONST_DECL)
{
/* If the declaration was explicitly qualified indicate
that. The semantics of `A::f(3)' are different than
`f(3)' if `f' is virtual. */
- *idk = (scope
+ *idk = (scope
? CP_ID_KIND_QUALIFIED
: (TREE_CODE (decl) == TEMPLATE_ID_EXPR
? CP_ID_KIND_TEMPLATE_ID
/* A template-id where the name of the template was not resolved
is definitely dependent. */
else if (TREE_CODE (decl) == TEMPLATE_ID_EXPR
- && (TREE_CODE (TREE_OPERAND (decl, 0))
+ && (TREE_CODE (TREE_OPERAND (decl, 0))
== IDENTIFIER_NODE))
dependent_p = true;
/* For anything except an overloaded function, just check its
type. */
else if (!is_overloaded_fn (decl))
- dependent_p
+ dependent_p
= dependent_type_p (TREE_TYPE (decl));
/* For a set of overloaded functions, check each of the
functions. */
dependent. */
if (scope)
{
- if (TYPE_P (scope))
- *qualifying_class = scope;
/* Since this name was dependent, the expression isn't
constant -- yet. No error is issued because it might
be constant when things are instantiated. */
if (integral_constant_expression_p)
*non_integral_constant_expression_p = true;
- if (TYPE_P (scope) && dependent_type_p (scope))
- return build_nt (SCOPE_REF, scope, id_expression);
- else if (TYPE_P (scope) && DECL_P (decl))
- return convert_from_reference
- (build2 (SCOPE_REF, TREE_TYPE (decl), scope, id_expression));
- else
- return convert_from_reference (decl);
+ 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 (/*type=*/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;
}
/* A TEMPLATE_ID already contains all the information we
need. */
if (TREE_CODE (id_expression) == TEMPLATE_ID_EXPR)
return id_expression;
- /* Since this name was dependent, the expression isn't
- constant -- yet. No error is issued because it might be
- constant when things are instantiated. */
- if (integral_constant_expression_p)
- *non_integral_constant_expression_p = true;
*idk = CP_ID_KIND_UNQUALIFIED_DEPENDENT;
/* If we found a variable, then name lookup during the
instantiation will always resolve to the same VAR_DECL
}
/* Only certain kinds of names are allowed in constant
- expression. Enumerators and template parameters have already
- been handled above. */
+ expression. Enumerators and template parameters have already
+ been handled above. */
if (integral_constant_expression_p
- && !DECL_INTEGRAL_CONSTANT_VAR_P (decl))
+ && ! DECL_INTEGRAL_CONSTANT_VAR_P (decl)
+ && ! builtin_valid_in_constant_expr_p (decl))
{
if (!allow_non_integral_constant_expression_p)
{
}
*non_integral_constant_expression_p = true;
}
-
+
if (TREE_CODE (decl) == NAMESPACE_DECL)
{
error ("use of namespace %qD as expression", decl);
if (scope)
{
- decl = (adjust_result_of_qualified_name_lookup
+ 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))
- *qualifying_class = scope;
+ 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 = build2 (SCOPE_REF, TREE_TYPE (r), scope, decl);
+
+ if (processing_template_decl && TYPE_P (scope))
+ r = build_qualified_name (TREE_TYPE (r),
+ scope, decl,
+ template_p);
decl = r;
}
}
if (!really_overloaded_fn (decl))
mark_used (first_fn);
- if (TREE_CODE (first_fn) == FUNCTION_DECL
+ if (!template_arg_p
+ && TREE_CODE (first_fn) == FUNCTION_DECL
&& DECL_FUNCTION_MEMBER_P (first_fn)
&& !shared_member_p (decl))
{
/* A set of member functions. */
decl = maybe_dummy_object (DECL_CONTEXT (first_fn), 0);
- return finish_class_member_access_expr (decl, id_expression);
+ return finish_class_member_access_expr (decl, id_expression,
+ /*template_p=*/false);
}
}
else
{
- if (TREE_CODE (decl) == VAR_DECL
- || TREE_CODE (decl) == PARM_DECL
- || TREE_CODE (decl) == RESULT_DECL)
- {
- tree context = decl_function_context (decl);
-
- if (context != NULL_TREE && context != current_function_decl
- && ! TREE_STATIC (decl))
- {
- error ("use of %s from containing function",
- (TREE_CODE (decl) == VAR_DECL
- ? "%<auto%> variable" : "parameter"));
- cp_error_at (" %q#D declared here", decl);
- return error_mark_node;
- }
- }
-
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 = convert_from_reference (decl);
}
-
- /* Resolve references to variables of anonymous unions
- into COMPONENT_REFs. */
- if (TREE_CODE (decl) == ALIAS_DECL)
- decl = unshare_expr (DECL_INITIAL (decl));
}
if (TREE_DEPRECATED (decl))
with equivalent CALL_EXPRs. */
static tree
-simplify_aggr_init_exprs_r (tree* tp,
- int* walk_subtrees,
- void* data ATTRIBUTE_UNUSED)
+simplify_aggr_init_exprs_r (tree* tp,
+ int* walk_subtrees,
+ void* data ATTRIBUTE_UNUSED)
{
/* We don't need to walk into types; there's nothing in a type that
needs simplification. (And, furthermore, there are places we
style = arg;
}
- if (style == ctor || style == arg)
+ if (style == ctor)
{
- /* Pass the address of the slot. If this is a constructor, we
- replace the first argument; otherwise, we tack on a new one. */
+ /* Replace the first argument to the ctor with the address of the
+ slot. */
tree addr;
- if (style == ctor)
- args = TREE_CHAIN (args);
-
+ args = TREE_CHAIN (args);
cxx_mark_addressable (slot);
addr = build1 (ADDR_EXPR, build_pointer_type (type), slot);
- if (style == arg)
- {
- /* The return type might have different cv-quals from the slot. */
- tree fntype = TREE_TYPE (TREE_TYPE (fn));
-
- gcc_assert (TREE_CODE (fntype) == FUNCTION_TYPE
- || TREE_CODE (fntype) == METHOD_TYPE);
- addr = convert (build_pointer_type (TREE_TYPE (fntype)), addr);
- }
-
args = tree_cons (NULL_TREE, addr, args);
}
- call_expr = build3 (CALL_EXPR,
+ call_expr = build3 (CALL_EXPR,
TREE_TYPE (TREE_TYPE (TREE_TYPE (fn))),
fn, args, NULL_TREE);
if (style == arg)
- /* Tell the backend that we've added our return slot to the argument
- list. */
- CALL_EXPR_HAS_RETURN_SLOT_ADDR (call_expr) = 1;
+ {
+ /* Just mark it addressable here, and leave the rest to
+ expand_call{,_inline}. */
+ 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)
{
/* If we're using the non-reentrant PCC calling convention, then we
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;
if (DECL_VIRTUAL_P (fn))
{
tree thunk;
-
+
for (thunk = DECL_THUNKS (fn); thunk; thunk = TREE_CHAIN (thunk))
{
if (!THUNK_ALIAS (thunk))
if (DECL_RESULT_THUNK_P (thunk))
{
tree probe;
-
+
for (probe = DECL_THUNKS (thunk);
probe; probe = TREE_CHAIN (probe))
use_thunk (probe, /*emit_p=*/1);
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. */
+ 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));
/* Normally, collection only occurs in rest_of_compilation. So,
if we don't collect here, we never collect junk generated
during the processing of templates until we hit a
- non-template function. */
- ggc_collect ();
+ non-template function. It's not safe to do this inside a
+ nested class, though, as the parser may have local state that
+ is not a GC root. */
+ if (!function_depth)
+ ggc_collect ();
return;
}
these functions so that it can inline them as appropriate. */
if (DECL_DECLARED_INLINE_P (fn) || DECL_IMPLICIT_INSTANTIATION (fn))
{
- if (!at_eof)
+ if (DECL_INTERFACE_KNOWN (fn))
+ /* We've already made a decision as to how this function will
+ be handled. */;
+ else if (!at_eof)
{
DECL_EXTERNAL (fn) = 1;
DECL_NOT_REALLY_EXTERN (fn) = 1;
note_vague_linkage_fn (fn);
+ /* A non-template inline function with external linkage will
+ always be COMDAT. As we must eventually determine the
+ linkage of all functions, and as that causes writes to
+ the data mapped in from the PCH file, it's advantageous
+ to mark the functions at this point. */
+ if (!DECL_IMPLICIT_INSTANTIATION (fn))
+ {
+ /* This function must have external linkage, as
+ otherwise DECL_INTERFACE_KNOWN would have been
+ set. */
+ gcc_assert (TREE_PUBLIC (fn));
+ comdat_linkage (fn);
+ DECL_INTERFACE_KNOWN (fn) = 1;
+ }
}
else
import_export_decl (fn);