#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "tm.h"
#include "tree.h"
#include "rtl.h"
#include "expr.h"
#include "flags.h"
#include "cp-tree.h"
#include "decl.h"
#include "output.h"
#include "except.h"
#include "toplev.h"
#include "timevar.h"
#include "cpplib.h"
#include "target.h"
#include "c-common.h"
#include "tree-mudflap.h"
#include "cgraph.h"
#include "tree-inline.h"
#include "c-pragma.h"
#include "tree-dump.h"
#include "intl.h"
#include "tree-iterator.h"
extern cpp_reader *parse_in;
typedef struct priority_info_s {
int initializations_p;
int destructions_p;
} *priority_info;
static void mark_vtable_entries (tree);
static bool maybe_emit_vtables (tree);
static bool acceptable_java_type (tree);
static tree start_objects (int, int);
static void finish_objects (int, int, tree);
static tree start_static_storage_duration_function (unsigned);
static void finish_static_storage_duration_function (tree);
static priority_info get_priority_info (int);
static void do_static_initialization_or_destruction (tree, bool);
static void one_static_initialization_or_destruction (tree, tree, bool, priority_info);
static void generate_ctor_or_dtor_function (bool, int, location_t *);
static int generate_ctor_and_dtor_functions_for_priority (splay_tree_node,
void *);
static tree prune_vars_needing_no_initialization (tree *);
static void write_out_vars (tree);
static void import_export_class (tree);
static tree get_guard_bits (tree);
static void determine_visibility_from_class (tree, tree);
static GTY(()) VEC(tree,gc) *pending_statics;
static GTY(()) VEC(tree,gc) *deferred_fns;
int at_eof;
tree static_ctors;
tree static_dtors;
tree
build_memfn_type (tree fntype, tree ctype, cp_cv_quals quals)
{
tree raises;
int type_quals;
if (fntype == error_mark_node || ctype == error_mark_node)
return error_mark_node;
type_quals = quals & ~TYPE_QUAL_RESTRICT;
ctype = cp_build_qualified_type (ctype, type_quals);
fntype = build_method_type_directly (ctype, TREE_TYPE (fntype),
(TREE_CODE (fntype) == METHOD_TYPE
? TREE_CHAIN (TYPE_ARG_TYPES (fntype))
: TYPE_ARG_TYPES (fntype)));
raises = TYPE_RAISES_EXCEPTIONS (fntype);
if (raises)
fntype = build_exception_variant (fntype, raises);
return fntype;
}
tree
cp_build_parm_decl (tree name, tree type)
{
tree parm = build_decl (PARM_DECL, name, type);
if (!processing_template_decl)
DECL_ARG_TYPE (parm) = type_passed_as (type);
return parm;
}
tree
build_artificial_parm (tree name, tree type)
{
tree parm = cp_build_parm_decl (name, type);
DECL_ARTIFICIAL (parm) = 1;
TREE_READONLY (parm) = 1;
return parm;
}
void
maybe_retrofit_in_chrg (tree fn)
{
tree basetype, arg_types, parms, parm, fntype;
if (DECL_HAS_IN_CHARGE_PARM_P (fn))
return;
if (processing_template_decl)
return;
if (DECL_CONSTRUCTOR_P (fn)
&& !CLASSTYPE_VBASECLASSES (DECL_CONTEXT (fn)))
return;
arg_types = TYPE_ARG_TYPES (TREE_TYPE (fn));
basetype = TREE_TYPE (TREE_VALUE (arg_types));
arg_types = TREE_CHAIN (arg_types);
parms = TREE_CHAIN (DECL_ARGUMENTS (fn));
if (CLASSTYPE_VBASECLASSES (DECL_CONTEXT (fn)))
{
parm = build_artificial_parm (vtt_parm_identifier, vtt_parm_type);
TREE_CHAIN (parm) = parms;
parms = parm;
arg_types = hash_tree_chain (vtt_parm_type, arg_types);
DECL_HAS_VTT_PARM_P (fn) = 1;
}
parm = build_artificial_parm (in_charge_identifier, integer_type_node);
TREE_CHAIN (parm) = parms;
parms = parm;
arg_types = hash_tree_chain (integer_type_node, arg_types);
TREE_CHAIN (DECL_ARGUMENTS (fn)) = parms;
fntype = build_method_type_directly (basetype, TREE_TYPE (TREE_TYPE (fn)),
arg_types);
if (TYPE_RAISES_EXCEPTIONS (TREE_TYPE (fn)))
fntype = build_exception_variant (fntype,
TYPE_RAISES_EXCEPTIONS (TREE_TYPE (fn)));
TREE_TYPE (fn) = fntype;
DECL_HAS_IN_CHARGE_PARM_P (fn) = 1;
}
void
grokclassfn (tree ctype, tree function, enum overload_flags flags)
{
tree fn_name = DECL_NAME (function);
SET_DECL_LANGUAGE (function, lang_cplusplus);
if (fn_name == NULL_TREE)
{
error ("name missing for member function");
fn_name = get_identifier ("<anonymous>");
DECL_NAME (function) = fn_name;
}
DECL_CONTEXT (function) = ctype;
if (flags == DTOR_FLAG)
DECL_DESTRUCTOR_P (function) = 1;
if (flags == DTOR_FLAG || DECL_CONSTRUCTOR_P (function))
maybe_retrofit_in_chrg (function);
}
tree
grok_array_decl (tree array_expr, tree index_exp)
{
tree type;
tree expr;
tree orig_array_expr = array_expr;
tree orig_index_exp = index_exp;
if (error_operand_p (array_expr) || error_operand_p (index_exp))
return error_mark_node;
if (processing_template_decl)
{
if (type_dependent_expression_p (array_expr)
|| type_dependent_expression_p (index_exp))
return build_min_nt (ARRAY_REF, array_expr, index_exp,
NULL_TREE, NULL_TREE);
array_expr = build_non_dependent_expr (array_expr);
index_exp = build_non_dependent_expr (index_exp);
}
type = TREE_TYPE (array_expr);
gcc_assert (type);
type = non_reference (type);
if (IS_AGGR_TYPE (type) || IS_AGGR_TYPE (TREE_TYPE (index_exp)))
expr = build_new_op (ARRAY_REF, LOOKUP_NORMAL,
array_expr, index_exp, NULL_TREE,
NULL);
else
{
tree p1, p2, i1, i2;
if (TREE_CODE (type) == ARRAY_TYPE)
p1 = array_expr;
else
p1 = build_expr_type_conversion (WANT_POINTER, array_expr, false);
if (TREE_CODE (TREE_TYPE (index_exp)) == ARRAY_TYPE)
p2 = index_exp;
else
p2 = build_expr_type_conversion (WANT_POINTER, index_exp, false);
i1 = build_expr_type_conversion (WANT_INT | WANT_ENUM, array_expr,
false);
i2 = build_expr_type_conversion (WANT_INT | WANT_ENUM, index_exp,
false);
if ((p1 && i2) && (i1 && p2))
error ("ambiguous conversion for array subscript");
if (p1 && i2)
array_expr = p1, index_exp = i2;
else if (i1 && p2)
array_expr = p2, index_exp = i1;
else
{
error ("invalid types %<%T[%T]%> for array subscript",
type, TREE_TYPE (index_exp));
return error_mark_node;
}
if (array_expr == error_mark_node || index_exp == error_mark_node)
error ("ambiguous conversion for array subscript");
expr = build_array_ref (array_expr, index_exp);
}
if (processing_template_decl && expr != error_mark_node)
return build_min_non_dep (ARRAY_REF, expr, orig_array_expr, orig_index_exp,
NULL_TREE, NULL_TREE);
return expr;
}
tree
delete_sanity (tree exp, tree size, bool doing_vec, int use_global_delete)
{
tree t, type;
if (exp == error_mark_node)
return exp;
if (processing_template_decl)
{
t = build_min (DELETE_EXPR, void_type_node, exp, size);
DELETE_EXPR_USE_GLOBAL (t) = use_global_delete;
DELETE_EXPR_USE_VEC (t) = doing_vec;
TREE_SIDE_EFFECTS (t) = 1;
return t;
}
if (TREE_CODE (exp) == VAR_DECL
&& TREE_CODE (TREE_TYPE (exp)) == ARRAY_TYPE)
warning (0, "deleting array %q#D", exp);
t = build_expr_type_conversion (WANT_POINTER, exp, true);
if (t == NULL_TREE || t == error_mark_node)
{
error ("type %q#T argument given to %<delete%>, expected pointer",
TREE_TYPE (exp));
return error_mark_node;
}
type = TREE_TYPE (t);
if (TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE)
{
error ("cannot delete a function. Only pointer-to-objects are "
"valid arguments to %<delete%>");
return error_mark_node;
}
if (TREE_CODE (TREE_TYPE (type)) == VOID_TYPE)
{
warning (0, "deleting %qT is undefined", type);
doing_vec = 0;
}
if (integer_zerop (t))
return build1 (NOP_EXPR, void_type_node, t);
if (doing_vec)
return build_vec_delete (t, NULL_TREE,
sfk_deleting_destructor,
use_global_delete);
else
return build_delete (type, t, sfk_deleting_destructor,
LOOKUP_NORMAL, use_global_delete);
}
void
check_member_template (tree tmpl)
{
tree decl;
gcc_assert (TREE_CODE (tmpl) == TEMPLATE_DECL);
decl = DECL_TEMPLATE_RESULT (tmpl);
if (TREE_CODE (decl) == FUNCTION_DECL
|| (TREE_CODE (decl) == TYPE_DECL
&& IS_AGGR_TYPE (TREE_TYPE (decl))))
{
gcc_assert (!current_function_decl);
gcc_assert (!(TREE_CODE (decl) == FUNCTION_DECL
&& DECL_VIRTUAL_P (decl)));
DECL_IGNORED_P (tmpl) = 1;
}
else
error ("template declaration of %q#D", decl);
}
static bool
acceptable_java_type (tree type)
{
if (type == error_mark_node)
return false;
if (TREE_CODE (type) == VOID_TYPE || TYPE_FOR_JAVA (type))
return true;
if (TREE_CODE (type) == POINTER_TYPE || TREE_CODE (type) == REFERENCE_TYPE)
{
type = TREE_TYPE (type);
if (TREE_CODE (type) == RECORD_TYPE)
{
tree args; int i;
if (! TYPE_FOR_JAVA (type))
return false;
if (! CLASSTYPE_TEMPLATE_INFO (type))
return true;
args = CLASSTYPE_TI_ARGS (type);
i = TREE_VEC_LENGTH (args);
while (--i >= 0)
{
type = TREE_VEC_ELT (args, i);
if (TREE_CODE (type) == POINTER_TYPE)
type = TREE_TYPE (type);
if (! TYPE_FOR_JAVA (type))
return false;
}
return true;
}
}
return false;
}
bool
check_java_method (tree method)
{
bool jerr = false;
tree arg_types = TYPE_ARG_TYPES (TREE_TYPE (method));
tree ret_type = TREE_TYPE (TREE_TYPE (method));
if (!acceptable_java_type (ret_type))
{
error ("Java method %qD has non-Java return type %qT",
method, ret_type);
jerr = true;
}
arg_types = TREE_CHAIN (arg_types);
if (DECL_HAS_IN_CHARGE_PARM_P (method))
arg_types = TREE_CHAIN (arg_types);
if (DECL_HAS_VTT_PARM_P (method))
arg_types = TREE_CHAIN (arg_types);
for (; arg_types != NULL_TREE; arg_types = TREE_CHAIN (arg_types))
{
tree type = TREE_VALUE (arg_types);
if (!acceptable_java_type (type))
{
if (type != error_mark_node)
error ("Java method %qD has non-Java parameter type %qT",
method, type);
jerr = true;
}
}
return !jerr;
}
tree
check_classfn (tree ctype, tree function, tree template_parms)
{
int ix;
bool is_template;
tree pushed_scope;
if (DECL_USE_TEMPLATE (function)
&& !(TREE_CODE (function) == TEMPLATE_DECL
&& DECL_TEMPLATE_SPECIALIZATION (function))
&& DECL_MEMBER_TEMPLATE_P (DECL_TI_TEMPLATE (function)))
return NULL_TREE;
if (TREE_CODE (function) == TEMPLATE_DECL)
{
gcc_assert (!template_parms
|| comp_template_parms (template_parms,
DECL_TEMPLATE_PARMS (function)));
template_parms = DECL_TEMPLATE_PARMS (function);
}
is_template = (template_parms != NULL_TREE);
pushed_scope = push_scope (ctype);
ix = class_method_index_for_fn (complete_type (ctype), function);
if (ix >= 0)
{
VEC(tree,gc) *methods = CLASSTYPE_METHOD_VEC (ctype);
tree fndecls, fndecl = 0;
bool is_conv_op;
const char *format = NULL;
for (fndecls = VEC_index (tree, methods, ix);
fndecls; fndecls = OVL_NEXT (fndecls))
{
tree p1, p2;
fndecl = OVL_CURRENT (fndecls);
p1 = TYPE_ARG_TYPES (TREE_TYPE (function));
p2 = TYPE_ARG_TYPES (TREE_TYPE (fndecl));
if (DECL_STATIC_FUNCTION_P (fndecl)
&& TREE_CODE (TREE_TYPE (function)) == METHOD_TYPE)
p1 = TREE_CHAIN (p1);
if (is_template != (TREE_CODE (fndecl) == TEMPLATE_DECL))
continue;
if (same_type_p (TREE_TYPE (TREE_TYPE (function)),
TREE_TYPE (TREE_TYPE (fndecl)))
&& compparms (p1, p2)
&& (!is_template
|| comp_template_parms (template_parms,
DECL_TEMPLATE_PARMS (fndecl)))
&& (DECL_TEMPLATE_SPECIALIZATION (function)
== DECL_TEMPLATE_SPECIALIZATION (fndecl))
&& (!DECL_TEMPLATE_SPECIALIZATION (function)
|| (DECL_TI_TEMPLATE (function)
== DECL_TI_TEMPLATE (fndecl))))
break;
}
if (fndecls)
{
if (pushed_scope)
pop_scope (pushed_scope);
return OVL_CURRENT (fndecls);
}
error ("prototype for %q#D does not match any in class %qT",
function, ctype);
is_conv_op = DECL_CONV_FN_P (fndecl);
if (is_conv_op)
ix = CLASSTYPE_FIRST_CONVERSION_SLOT;
fndecls = VEC_index (tree, methods, ix);
while (fndecls)
{
fndecl = OVL_CURRENT (fndecls);
fndecls = OVL_NEXT (fndecls);
if (!fndecls && is_conv_op)
{
if (VEC_length (tree, methods) > (size_t) ++ix)
{
fndecls = VEC_index (tree, methods, ix);
if (!DECL_CONV_FN_P (OVL_CURRENT (fndecls)))
{
fndecls = NULL_TREE;
is_conv_op = false;
}
}
else
is_conv_op = false;
}
if (format)
format = " %+#D";
else if (fndecls)
format = N_("candidates are: %+#D");
else
format = N_("candidate is: %+#D");
error (format, fndecl);
}
}
else if (!COMPLETE_TYPE_P (ctype))
cxx_incomplete_type_error (function, ctype);
else
error ("no %q#D member function declared in class %qT",
function, ctype);
if (COMPLETE_TYPE_P (ctype))
add_method (ctype, function, NULL_TREE);
if (pushed_scope)
pop_scope (pushed_scope);
return NULL_TREE;
}
void
note_vague_linkage_fn (tree decl)
{
if (!DECL_DEFERRED_FN (decl))
{
DECL_DEFERRED_FN (decl) = 1;
DECL_DEFER_OUTPUT (decl) = 1;
VEC_safe_push (tree, gc, deferred_fns, decl);
}
}
void
finish_static_data_member_decl (tree decl,
tree init, bool init_const_expr_p,
tree asmspec_tree,
int flags)
{
DECL_CONTEXT (decl) = current_class_type;
if (! processing_template_decl)
VEC_safe_push (tree, gc, pending_statics, decl);
if (LOCAL_CLASS_P (current_class_type))
pedwarn ("local class %q#T shall not have static data member %q#D",
current_class_type, decl);
if (init != NULL_TREE && TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (decl)))
{
static int explained = 0;
error ("initializer invalid for static member with constructor");
if (!explained)
{
error ("(an out of class initialization is required)");
explained = 1;
}
init = NULL_TREE;
}
if (CP_TYPE_CONST_P (TREE_TYPE (decl)) && init == 0)
TREE_USED (decl) = 1;
DECL_INITIAL (decl) = init;
DECL_IN_AGGR_P (decl) = 1;
cp_finish_decl (decl, init, init_const_expr_p, asmspec_tree, flags);
}
tree
grokfield (const cp_declarator *declarator,
cp_decl_specifier_seq *declspecs,
tree init, bool init_const_expr_p,
tree asmspec_tree,
tree attrlist)
{
tree value;
const char *asmspec = 0;
int flags = LOOKUP_ONLYCONVERTING;
if (init
&& TREE_CODE (init) == TREE_LIST
&& TREE_VALUE (init) == error_mark_node
&& TREE_CHAIN (init) == NULL_TREE)
init = NULL_TREE;
value = grokdeclarator (declarator, declspecs, FIELD, init != 0, &attrlist);
if (! value || error_operand_p (value))
return error_mark_node;
if (TREE_CODE (value) == TYPE_DECL && init)
{
error ("typedef %qD is initialized (use __typeof__ instead)", value);
init = NULL_TREE;
}
if (value == void_type_node)
return value;
if ((TREE_CODE (value) == FUNCTION_DECL
|| TREE_CODE (value) == TEMPLATE_DECL)
&& DECL_CONTEXT (value) != current_class_type)
return value;
if (DECL_NAME (value) != NULL_TREE
&& IDENTIFIER_POINTER (DECL_NAME (value))[0] == '_'
&& ! strcmp (IDENTIFIER_POINTER (DECL_NAME (value)), "_vptr"))
error ("member %qD conflicts with virtual function table field name",
value);
if (TREE_CODE (value) == TYPE_DECL)
{
DECL_NONLOCAL (value) = 1;
DECL_CONTEXT (value) = current_class_type;
if (processing_template_decl)
value = push_template_decl (value);
if (attrlist)
{
tree type = TREE_TYPE (value);
if (TREE_CODE (type) == TEMPLATE_TYPE_PARM
|| TREE_CODE (type) == BOUND_TEMPLATE_TEMPLATE_PARM)
sorry ("applying attributes to template parameters is not implemented");
else
cplus_decl_attributes (&value, attrlist, 0);
}
return value;
}
if (DECL_IN_AGGR_P (value))
{
error ("%qD is already defined in %qT", value, DECL_CONTEXT (value));
return void_type_node;
}
if (asmspec_tree && asmspec_tree != error_mark_node)
asmspec = TREE_STRING_POINTER (asmspec_tree);
if (init)
{
if (TREE_CODE (value) == FUNCTION_DECL)
{
if (TREE_CODE (TREE_TYPE (value)) == METHOD_TYPE)
{
gcc_assert (error_operand_p (init) || integer_zerop (init));
DECL_PURE_VIRTUAL_P (value) = 1;
}
else
{
gcc_assert (TREE_CODE (TREE_TYPE (value)) == FUNCTION_TYPE);
error ("initializer specified for static member function %qD",
value);
}
}
else if (pedantic && TREE_CODE (value) != VAR_DECL)
init = NULL_TREE;
else if (!processing_template_decl)
{
if (TREE_CODE (init) == CONSTRUCTOR)
init = digest_init (TREE_TYPE (value), init);
else
init = integral_constant_value (init);
if (init != error_mark_node && !TREE_CONSTANT (init))
{
if (TREE_CODE (TREE_TYPE (value)) != REFERENCE_TYPE
|| (TREE_STATIC (init) == 0
&& (!DECL_P (init) || DECL_EXTERNAL (init) == 0)))
{
error ("field initializer is not constant");
init = error_mark_node;
}
}
}
}
if (processing_template_decl
&& (TREE_CODE (value) == VAR_DECL || TREE_CODE (value) == FUNCTION_DECL))
{
value = push_template_decl (value);
if (error_operand_p (value))
return error_mark_node;
}
if (attrlist)
cplus_decl_attributes (&value, attrlist, 0);
switch (TREE_CODE (value))
{
case VAR_DECL:
finish_static_data_member_decl (value, init, init_const_expr_p,
asmspec_tree, flags);
return value;
case FIELD_DECL:
if (asmspec)
error ("%<asm%> specifiers are not permitted on non-static data members");
if (DECL_INITIAL (value) == error_mark_node)
init = error_mark_node;
cp_finish_decl (value, init, false,
NULL_TREE, flags);
DECL_INITIAL (value) = init;
DECL_IN_AGGR_P (value) = 1;
return value;
case FUNCTION_DECL:
if (asmspec)
set_user_assembler_name (value, asmspec);
cp_finish_decl (value,
NULL_TREE,
false,
asmspec_tree, flags);
if (DECL_FRIEND_P (value))
return void_type_node;
DECL_IN_AGGR_P (value) = 1;
return value;
default:
gcc_unreachable ();
}
return NULL_TREE;
}
tree
grokbitfield (const cp_declarator *declarator,
cp_decl_specifier_seq *declspecs, tree width)
{
tree value = grokdeclarator (declarator, declspecs, BITFIELD, 0, NULL);
if (value == error_mark_node)
return NULL_TREE;
if (TREE_CODE (value) == VOID_TYPE)
return void_type_node;
if (!INTEGRAL_TYPE_P (TREE_TYPE (value))
&& (POINTER_TYPE_P (value)
|| !dependent_type_p (TREE_TYPE (value))))
{
error ("bit-field %qD with non-integral type", value);
return error_mark_node;
}
if (TREE_CODE (value) == TYPE_DECL)
{
error ("cannot declare %qD to be a bit-field type", value);
return NULL_TREE;
}
if (TREE_CODE (value) == FUNCTION_DECL)
{
error ("cannot declare bit-field %qD with function type",
DECL_NAME (value));
return NULL_TREE;
}
if (DECL_IN_AGGR_P (value))
{
error ("%qD is already defined in the class %qT", value,
DECL_CONTEXT (value));
return void_type_node;
}
if (TREE_STATIC (value))
{
error ("static member %qD cannot be a bit-field", value);
return NULL_TREE;
}
finish_decl (value, NULL_TREE, NULL_TREE);
if (width != error_mark_node)
{
constant_expression_warning (width);
DECL_INITIAL (value) = width;
SET_DECL_C_BIT_FIELD (value);
}
DECL_IN_AGGR_P (value) = 1;
return value;
}
void
cplus_decl_attributes (tree *decl, tree attributes, int flags)
{
if (*decl == NULL_TREE || *decl == void_type_node
|| *decl == error_mark_node)
return;
if (TREE_CODE (*decl) == TEMPLATE_DECL)
decl = &DECL_TEMPLATE_RESULT (*decl);
decl_attributes (decl, attributes, flags);
if (TREE_CODE (*decl) == TYPE_DECL)
SET_IDENTIFIER_TYPE_VALUE (DECL_NAME (*decl), TREE_TYPE (*decl));
}
static tree
build_anon_union_vars (tree type, tree object)
{
tree main_decl = NULL_TREE;
tree field;
if (TREE_CODE (type) != UNION_TYPE)
error ("anonymous struct not inside named type");
for (field = TYPE_FIELDS (type);
field != NULL_TREE;
field = TREE_CHAIN (field))
{
tree decl;
tree ref;
if (DECL_ARTIFICIAL (field))
continue;
if (TREE_CODE (field) != FIELD_DECL)
{
pedwarn ("%q+#D invalid; an anonymous union can only "
"have non-static data members", field);
continue;
}
if (TREE_PRIVATE (field))
pedwarn ("private member %q+#D in anonymous union", field);
else if (TREE_PROTECTED (field))
pedwarn ("protected member %q+#D in anonymous union", field);
if (processing_template_decl)
ref = build_min_nt (COMPONENT_REF, object,
DECL_NAME (field), NULL_TREE);
else
ref = build_class_member_access_expr (object, field, NULL_TREE,
false);
if (DECL_NAME (field))
{
tree base;
decl = build_decl (VAR_DECL, DECL_NAME (field), TREE_TYPE (field));
DECL_ANON_UNION_VAR_P (decl) = 1;
base = get_base_address (object);
TREE_PUBLIC (decl) = TREE_PUBLIC (base);
TREE_STATIC (decl) = TREE_STATIC (base);
DECL_EXTERNAL (decl) = DECL_EXTERNAL (base);
SET_DECL_VALUE_EXPR (decl, ref);
DECL_HAS_VALUE_EXPR_P (decl) = 1;
decl = pushdecl (decl);
}
else if (ANON_AGGR_TYPE_P (TREE_TYPE (field)))
decl = build_anon_union_vars (TREE_TYPE (field), ref);
else
decl = 0;
if (main_decl == NULL_TREE)
main_decl = decl;
}
return main_decl;
}
void
finish_anon_union (tree anon_union_decl)
{
tree type;
tree main_decl;
bool public_p;
if (anon_union_decl == error_mark_node)
return;
type = TREE_TYPE (anon_union_decl);
public_p = TREE_PUBLIC (anon_union_decl);
DECL_CONTEXT (anon_union_decl) = DECL_CONTEXT (TYPE_NAME (type));
if (TYPE_FIELDS (type) == NULL_TREE)
return;
if (public_p)
{
error ("namespace-scope anonymous aggregates must be static");
return;
}
main_decl = build_anon_union_vars (type, anon_union_decl);
if (main_decl == error_mark_node)
return;
if (main_decl == NULL_TREE)
{
warning (0, "anonymous union with no members");
return;
}
if (!processing_template_decl)
{
DECL_NAME (anon_union_decl) = DECL_NAME (main_decl);
mangle_decl (anon_union_decl);
DECL_NAME (anon_union_decl) = NULL_TREE;
}
pushdecl (anon_union_decl);
if (building_stmt_tree ()
&& at_function_scope_p ())
add_decl_expr (anon_union_decl);
else if (!processing_template_decl)
rest_of_decl_compilation (anon_union_decl,
toplevel_bindings_p (), at_eof);
}
tree
coerce_new_type (tree type)
{
int e = 0;
tree args = TYPE_ARG_TYPES (type);
gcc_assert (TREE_CODE (type) == FUNCTION_TYPE);
if (!same_type_p (TREE_TYPE (type), ptr_type_node))
{
e = 1;
error ("%<operator new%> must return type %qT", ptr_type_node);
}
if (!args || args == void_list_node
|| !same_type_p (TREE_VALUE (args), size_type_node))
{
e = 2;
if (args && args != void_list_node)
args = TREE_CHAIN (args);
pedwarn ("%<operator new%> takes type %<size_t%> (%qT) "
"as first parameter", size_type_node);
}
switch (e)
{
case 2:
args = tree_cons (NULL_TREE, size_type_node, args);
case 1:
type = build_exception_variant
(build_function_type (ptr_type_node, args),
TYPE_RAISES_EXCEPTIONS (type));
default:;
}
return type;
}
tree
coerce_delete_type (tree type)
{
int e = 0;
tree args = TYPE_ARG_TYPES (type);
gcc_assert (TREE_CODE (type) == FUNCTION_TYPE);
if (!same_type_p (TREE_TYPE (type), void_type_node))
{
e = 1;
error ("%<operator delete%> must return type %qT", void_type_node);
}
if (!args || args == void_list_node
|| !same_type_p (TREE_VALUE (args), ptr_type_node))
{
e = 2;
if (args && args != void_list_node)
args = TREE_CHAIN (args);
error ("%<operator delete%> takes type %qT as first parameter",
ptr_type_node);
}
switch (e)
{
case 2:
args = tree_cons (NULL_TREE, ptr_type_node, args);
case 1:
type = build_exception_variant
(build_function_type (void_type_node, args),
TYPE_RAISES_EXCEPTIONS (type));
default:;
}
return type;
}
static void
mark_vtable_entries (tree decl)
{
tree fnaddr;
unsigned HOST_WIDE_INT idx;
FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (DECL_INITIAL (decl)),
idx, fnaddr)
{
tree fn;
STRIP_NOPS (fnaddr);
if (TREE_CODE (fnaddr) != ADDR_EXPR
&& TREE_CODE (fnaddr) != FDESC_EXPR)
continue;
fn = TREE_OPERAND (fnaddr, 0);
TREE_ADDRESSABLE (fn) = 1;
if (DECL_THUNK_P (fn))
use_thunk (fn, 0);
mark_used (fn);
}
}
void
comdat_linkage (tree decl)
{
if (flag_weak)
make_decl_one_only (decl);
else if (TREE_CODE (decl) == FUNCTION_DECL
|| (TREE_CODE (decl) == VAR_DECL && DECL_ARTIFICIAL (decl)))
TREE_PUBLIC (decl) = 0;
else
{
if (DECL_INITIAL (decl) == 0
|| DECL_INITIAL (decl) == error_mark_node)
DECL_COMMON (decl) = 1;
else if (EMPTY_CONSTRUCTOR_P (DECL_INITIAL (decl)))
{
DECL_COMMON (decl) = 1;
DECL_INITIAL (decl) = error_mark_node;
}
else if (!DECL_EXPLICIT_INSTANTIATION (decl))
{
DECL_EXTERNAL (decl) = 1;
DECL_NOT_REALLY_EXTERN (decl) = 0;
}
}
if (DECL_LANG_SPECIFIC (decl))
DECL_COMDAT (decl) = 1;
}
void
maybe_make_one_only (tree decl)
{
if (! flag_weak)
return;
if (!TARGET_WEAK_NOT_IN_ARCHIVE_TOC
|| (! DECL_EXPLICIT_INSTANTIATION (decl)
&& ! DECL_TEMPLATE_SPECIALIZATION (decl)))
{
make_decl_one_only (decl);
if (TREE_CODE (decl) == VAR_DECL)
{
DECL_COMDAT (decl) = 1;
mark_decl_referenced (decl);
}
}
}
static void
import_export_class (tree ctype)
{
int import_export = 0;
gcc_assert (at_eof);
if (CLASSTYPE_INTERFACE_KNOWN (ctype))
return;
if (CLASSTYPE_INTERFACE_ONLY (ctype))
return;
if (lookup_attribute ("dllimport", TYPE_ATTRIBUTES (ctype)))
import_export = -1;
else if (lookup_attribute ("dllexport", TYPE_ATTRIBUTES (ctype)))
import_export = 1;
else if (CLASSTYPE_IMPLICIT_INSTANTIATION (ctype)
&& !flag_implicit_templates)
import_export = repo_export_class_p (ctype) ? 1 : -1;
else if (TYPE_POLYMORPHIC_P (ctype))
{
tree method = CLASSTYPE_KEY_METHOD (ctype);
if (method && (flag_weak || ! DECL_DECLARED_INLINE_P (method)))
import_export = (DECL_REALLY_EXTERN (method) ? -1 : 1);
}
if (MULTIPLE_SYMBOL_SPACES && import_export == -1)
import_export = 0;
if (targetm.cxx.import_export_class)
import_export = targetm.cxx.import_export_class (ctype, import_export);
if (import_export)
{
SET_CLASSTYPE_INTERFACE_KNOWN (ctype);
CLASSTYPE_INTERFACE_ONLY (ctype) = (import_export < 0);
}
}
static bool
var_finalized_p (tree var)
{
return cgraph_varpool_node (var)->finalized;
}
void
mark_needed (tree decl)
{
TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl)) = 1;
mark_decl_referenced (decl);
}
bool
decl_needed_p (tree decl)
{
gcc_assert (TREE_CODE (decl) == VAR_DECL
|| TREE_CODE (decl) == FUNCTION_DECL);
gcc_assert (at_eof);
if (TREE_PUBLIC (decl) && !DECL_COMDAT (decl))
return true;
if (TREE_USED (decl)
|| (DECL_ASSEMBLER_NAME_SET_P (decl)
&& TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl))))
return true;
return false;
}
static bool
maybe_emit_vtables (tree ctype)
{
tree vtbl;
tree primary_vtbl;
int needed = 0;
primary_vtbl = CLASSTYPE_VTABLES (ctype);
if (var_finalized_p (primary_vtbl))
return false;
if (TREE_TYPE (primary_vtbl) == void_type_node)
return false;
if (!targetm.cxx.key_method_may_be_inline ())
determine_key_method (ctype);
for (vtbl = CLASSTYPE_VTABLES (ctype); vtbl; vtbl = TREE_CHAIN (vtbl))
{
import_export_decl (vtbl);
if (DECL_NOT_REALLY_EXTERN (vtbl) && decl_needed_p (vtbl))
needed = 1;
}
if (!needed)
{
if (DECL_COMDAT (primary_vtbl)
&& CLASSTYPE_DEBUG_REQUESTED (ctype))
note_debug_info_needed (ctype);
return false;
}
for (vtbl = CLASSTYPE_VTABLES (ctype); vtbl; vtbl = TREE_CHAIN (vtbl))
{
mark_vtable_entries (vtbl);
if (TREE_TYPE (DECL_INITIAL (vtbl)) == 0)
{
tree expr = store_init_value (vtbl, DECL_INITIAL (vtbl));
gcc_assert (!expr);
}
DECL_EXTERNAL (vtbl) = 0;
rest_of_decl_compilation (vtbl, 1, 1);
if (flag_syntax_only)
TREE_ASM_WRITTEN (vtbl) = 1;
}
note_debug_info_needed (ctype);
return true;
}
enum { VISIBILITY_ANON = VISIBILITY_INTERNAL+1 };
static tree
min_vis_r (tree *tp, int *walk_subtrees, void *data)
{
int *vis_p = (int *)data;
if (! TYPE_P (*tp))
{
*walk_subtrees = 0;
}
else if (CLASS_TYPE_P (*tp))
{
if (!TREE_PUBLIC (TYPE_MAIN_DECL (*tp)))
{
*vis_p = VISIBILITY_ANON;
return *tp;
}
else if (CLASSTYPE_VISIBILITY (*tp) > *vis_p)
*vis_p = CLASSTYPE_VISIBILITY (*tp);
}
return NULL;
}
static int
type_visibility (tree type)
{
int vis = VISIBILITY_DEFAULT;
walk_tree_without_duplicates (&type, min_vis_r, &vis);
return vis;
}
static bool
constrain_visibility (tree decl, int visibility)
{
if (visibility == VISIBILITY_ANON)
{
if (!DECL_EXTERN_C_P (decl))
{
TREE_PUBLIC (decl) = 0;
DECL_INTERFACE_KNOWN (decl) = 1;
if (DECL_LANG_SPECIFIC (decl))
DECL_NOT_REALLY_EXTERN (decl) = 1;
}
}
else if (visibility > DECL_VISIBILITY (decl)
&& !DECL_VISIBILITY_SPECIFIED (decl))
{
DECL_VISIBILITY (decl) = visibility;
return true;
}
else if (visibility > DECL_VISIBILITY (decl)
&& DECL_VISIBILITY_SPECIFIED (decl)
&& !lookup_attribute ("visibility", DECL_ATTRIBUTES (decl))
&& !lookup_attribute ("dllexport", DECL_ATTRIBUTES (decl)))
{
DECL_VISIBILITY (decl) = visibility;
return true;
}
return false;
}
static void
constrain_visibility_for_template (tree decl, tree targs)
{
tree args = INNERMOST_TEMPLATE_ARGS (targs);
int i;
for (i = TREE_VEC_LENGTH (args); i > 0; --i)
{
int vis = 0;
tree arg = TREE_VEC_ELT (args, i-1);
if (TYPE_P (arg))
vis = type_visibility (arg);
else if (TREE_TYPE (arg) && POINTER_TYPE_P (TREE_TYPE (arg)))
{
STRIP_NOPS (arg);
if (TREE_CODE (arg) == ADDR_EXPR)
arg = TREE_OPERAND (arg, 0);
if (TREE_CODE (arg) == VAR_DECL
|| TREE_CODE (arg) == FUNCTION_DECL)
{
if (! TREE_PUBLIC (arg))
vis = VISIBILITY_ANON;
else
vis = DECL_VISIBILITY (arg);
}
}
if (vis)
constrain_visibility (decl, vis);
}
}
void
determine_visibility (tree decl)
{
tree class_type = NULL_TREE;
bool use_template;
if (!TREE_PUBLIC (decl))
return;
gcc_assert (!DECL_CLONED_FUNCTION_P (decl));
if (TREE_CODE (decl) == TYPE_DECL)
{
if (CLASS_TYPE_P (TREE_TYPE (decl)))
use_template = CLASSTYPE_USE_TEMPLATE (TREE_TYPE (decl));
else if (TYPE_TEMPLATE_INFO (TREE_TYPE (decl)))
use_template = 1;
else
use_template = 0;
}
else if (DECL_LANG_SPECIFIC (decl))
use_template = DECL_USE_TEMPLATE (decl);
else
use_template = 0;
if (TARGET_DLLIMPORT_DECL_ATTRIBUTES
&& lookup_attribute ("dllexport",
TREE_CODE (decl) == TYPE_DECL
? TYPE_ATTRIBUTES (TREE_TYPE (decl))
: DECL_ATTRIBUTES (decl)))
{
DECL_VISIBILITY (decl) = VISIBILITY_DEFAULT;
DECL_VISIBILITY_SPECIFIED (decl) = 1;
}
if (DECL_CLASS_SCOPE_P (decl))
class_type = DECL_CONTEXT (decl);
else
{
gcc_assert (TREE_CODE (decl) != VAR_DECL
|| !DECL_VTABLE_OR_VTT_P (decl));
if (DECL_FUNCTION_SCOPE_P (decl) && ! DECL_VISIBILITY_SPECIFIED (decl))
{
tree fn = DECL_CONTEXT (decl);
if (DECL_VISIBILITY_SPECIFIED (fn) || ! DECL_CLASS_SCOPE_P (fn))
{
DECL_VISIBILITY (decl) = DECL_VISIBILITY (fn);
DECL_VISIBILITY_SPECIFIED (decl) =
DECL_VISIBILITY_SPECIFIED (fn);
}
else
determine_visibility_from_class (decl, DECL_CONTEXT (fn));
use_template = 0;
}
else if (TREE_CODE (decl) == VAR_DECL && DECL_TINFO_P (decl)
&& flag_visibility_ms_compat)
{
tree underlying_type = TREE_TYPE (DECL_NAME (decl));
int underlying_vis = type_visibility (underlying_type);
if (underlying_vis == VISIBILITY_ANON
|| (TREE_CODE (underlying_type) == RECORD_TYPE
&& CLASSTYPE_VISIBILITY_SPECIFIED (underlying_type)))
constrain_visibility (decl, underlying_vis);
else
DECL_VISIBILITY (decl) = VISIBILITY_DEFAULT;
}
else if (TREE_CODE (decl) == VAR_DECL && DECL_TINFO_P (decl))
{
constrain_visibility
(decl, type_visibility (TREE_TYPE (DECL_NAME (decl))));
}
else if (use_template)
;
else if (! DECL_VISIBILITY_SPECIFIED (decl))
{
DECL_VISIBILITY (decl) = default_visibility;
DECL_VISIBILITY_SPECIFIED (decl) = visibility_options.inpragma;
}
}
if (use_template)
{
tree tinfo = (TREE_CODE (decl) == TYPE_DECL
? TYPE_TEMPLATE_INFO (TREE_TYPE (decl))
: DECL_TEMPLATE_INFO (decl));
tree args = TI_ARGS (tinfo);
if (args != error_mark_node)
{
int depth = TMPL_ARGS_DEPTH (args);
tree pattern = DECL_TEMPLATE_RESULT (TI_TEMPLATE (tinfo));
if (!DECL_VISIBILITY_SPECIFIED (decl))
{
DECL_VISIBILITY (decl) = DECL_VISIBILITY (pattern);
DECL_VISIBILITY_SPECIFIED (decl)
= DECL_VISIBILITY_SPECIFIED (pattern);
}
if (args && depth > template_class_depth (class_type))
constrain_visibility_for_template (decl, args);
}
}
if (class_type)
determine_visibility_from_class (decl, class_type);
if (decl_anon_ns_mem_p (decl))
constrain_visibility (decl, VISIBILITY_ANON);
else if (TREE_CODE (decl) != TYPE_DECL)
{
int tvis = type_visibility (TREE_TYPE (decl));
if (tvis == VISIBILITY_ANON
|| ! DECL_VISIBILITY_SPECIFIED (decl))
constrain_visibility (decl, tvis);
}
}
static void
determine_visibility_from_class (tree decl, tree class_type)
{
if (visibility_options.inlines_hidden
&& !processing_template_decl
&& ! DECL_VISIBILITY_SPECIFIED (decl)
&& TREE_CODE (decl) == FUNCTION_DECL
&& DECL_DECLARED_INLINE_P (decl)
&& (! DECL_LANG_SPECIFIC (decl)
|| ! DECL_EXPLICIT_INSTANTIATION (decl)))
DECL_VISIBILITY (decl) = VISIBILITY_HIDDEN;
else if (!DECL_VISIBILITY_SPECIFIED (decl))
{
DECL_VISIBILITY (decl) = CLASSTYPE_VISIBILITY (class_type);
DECL_VISIBILITY_SPECIFIED (decl)
= CLASSTYPE_VISIBILITY_SPECIFIED (class_type);
}
if (TREE_CODE (decl) == VAR_DECL
&& (DECL_TINFO_P (decl)
|| (DECL_VTABLE_OR_VTT_P (decl)
&& !DECL_CONSTRUCTION_VTABLE_P (decl)))
&& TREE_PUBLIC (decl)
&& !DECL_REALLY_EXTERN (decl)
&& !DECL_VISIBILITY_SPECIFIED (decl)
&& !CLASSTYPE_VISIBILITY_SPECIFIED (class_type))
targetm.cxx.determine_class_data_visibility (decl);
}
void
constrain_class_visibility (tree type)
{
tree binfo;
tree t;
int i;
int vis = type_visibility (type);
if (vis == VISIBILITY_ANON
|| DECL_IN_SYSTEM_HEADER (TYPE_MAIN_DECL (type)))
return;
if (CLASSTYPE_VISIBILITY_SPECIFIED (type))
vis = VISIBILITY_INTERNAL;
for (t = TYPE_FIELDS (type); t; t = TREE_CHAIN (t))
if (TREE_CODE (t) == FIELD_DECL && TREE_TYPE (t) != error_mark_node)
{
tree ftype = strip_array_types (TREE_TYPE (t));
int subvis = type_visibility (ftype);
if (subvis == VISIBILITY_ANON)
{
if (!in_main_input_context ())
warning (0, "\
%qT has a field %qD whose type uses the anonymous namespace",
type, t);
}
else if (IS_AGGR_TYPE (ftype)
&& vis < VISIBILITY_HIDDEN
&& subvis >= VISIBILITY_HIDDEN)
warning (OPT_Wattributes, "\
%qT declared with greater visibility than the type of its field %qD",
type, t);
}
binfo = TYPE_BINFO (type);
for (i = 0; BINFO_BASE_ITERATE (binfo, i, t); ++i)
{
int subvis = type_visibility (TREE_TYPE (t));
if (subvis == VISIBILITY_ANON)
{
if (!in_main_input_context())
warning (0, "\
%qT has a base %qT whose type uses the anonymous namespace",
type, TREE_TYPE (t));
}
else if (vis < VISIBILITY_HIDDEN
&& subvis >= VISIBILITY_HIDDEN)
warning (OPT_Wattributes, "\
%qT declared with greater visibility than its base %qT",
type, TREE_TYPE (t));
}
}
static bool
typeinfo_comdat (tree type)
{
tree binfo, base_binfo;
int j;
if (lookup_attribute ("weak", TYPE_ATTRIBUTES (type)))
return true;
for (binfo = TYPE_BINFO (type), j = 0;
BINFO_BASE_ITERATE (binfo, j, base_binfo); ++j)
{
if (typeinfo_comdat (BINFO_TYPE (base_binfo)))
return true;
}
return false;
}
void
import_export_decl (tree decl)
{
int emit_p;
bool comdat_p;
bool import_p;
tree class_type = NULL_TREE;
if (DECL_INTERFACE_KNOWN (decl))
return;
gcc_assert (at_eof);
gcc_assert (TREE_CODE (decl) == FUNCTION_DECL
|| TREE_CODE (decl) == VAR_DECL);
gcc_assert (TREE_PUBLIC (decl));
if (TREE_CODE (decl) == FUNCTION_DECL)
gcc_assert (DECL_IMPLICIT_INSTANTIATION (decl)
|| DECL_FRIEND_PSEUDO_TEMPLATE_INSTANTIATION (decl)
|| DECL_DECLARED_INLINE_P (decl));
else
gcc_assert (DECL_IMPLICIT_INSTANTIATION (decl)
|| DECL_VTABLE_OR_VTT_P (decl)
|| DECL_TINFO_P (decl));
gcc_assert (!DECL_REALLY_EXTERN (decl));
comdat_p = false;
import_p = false;
emit_p = repo_emit_p (decl);
if (emit_p == 0)
import_p = true;
else if (emit_p == 1)
{
if (TREE_CODE (decl) == VAR_DECL)
mark_needed (decl);
else if (DECL_MAYBE_IN_CHARGE_CONSTRUCTOR_P (decl)
|| DECL_MAYBE_IN_CHARGE_DESTRUCTOR_P (decl))
{
tree clone;
FOR_EACH_CLONE (clone, decl)
mark_needed (clone);
}
else
mark_needed (decl);
DECL_EXTERNAL (decl) = 0;
DECL_INTERFACE_KNOWN (decl) = 1;
return;
}
if (import_p)
;
else if (TREE_CODE (decl) == VAR_DECL && DECL_VTABLE_OR_VTT_P (decl))
{
class_type = DECL_CONTEXT (decl);
import_export_class (class_type);
if (TYPE_FOR_JAVA (class_type))
import_p = true;
else if (CLASSTYPE_INTERFACE_KNOWN (class_type)
&& CLASSTYPE_INTERFACE_ONLY (class_type))
import_p = true;
else if ((!flag_weak || TARGET_WEAK_NOT_IN_ARCHIVE_TOC)
&& !CLASSTYPE_USE_TEMPLATE (class_type)
&& CLASSTYPE_KEY_METHOD (class_type)
&& !DECL_DECLARED_INLINE_P (CLASSTYPE_KEY_METHOD (class_type)))
DECL_EXTERNAL (decl) = 0;
else if (CLASSTYPE_INTERFACE_KNOWN (class_type))
{
if (!flag_weak && CLASSTYPE_EXPLICIT_INSTANTIATION (class_type))
DECL_EXTERNAL (decl) = 0;
else
{
if (!CLASSTYPE_KEY_METHOD (class_type)
|| DECL_DECLARED_INLINE_P (CLASSTYPE_KEY_METHOD (class_type))
|| targetm.cxx.class_data_always_comdat ())
{
comdat_p = true;
mark_needed (decl);
}
}
}
else if (!flag_implicit_templates
&& CLASSTYPE_IMPLICIT_INSTANTIATION (class_type))
import_p = true;
else
comdat_p = true;
}
else if (TREE_CODE (decl) == VAR_DECL && DECL_TINFO_P (decl))
{
tree type = TREE_TYPE (DECL_NAME (decl));
if (CLASS_TYPE_P (type))
{
class_type = type;
import_export_class (type);
if (CLASSTYPE_INTERFACE_KNOWN (type)
&& TYPE_POLYMORPHIC_P (type)
&& CLASSTYPE_INTERFACE_ONLY (type)
&& flag_rtti)
import_p = true;
else
{
if (CLASSTYPE_INTERFACE_KNOWN (type)
&& !CLASSTYPE_INTERFACE_ONLY (type))
{
comdat_p = (targetm.cxx.class_data_always_comdat ()
|| (CLASSTYPE_KEY_METHOD (type)
&& DECL_DECLARED_INLINE_P (CLASSTYPE_KEY_METHOD (type)))
|| typeinfo_comdat (type));
mark_needed (decl);
if (!flag_weak)
{
comdat_p = false;
DECL_EXTERNAL (decl) = 0;
}
}
else
comdat_p = true;
}
}
else
comdat_p = true;
}
else if (DECL_TEMPLATE_INSTANTIATION (decl)
|| DECL_FRIEND_PSEUDO_TEMPLATE_INSTANTIATION (decl))
{
if (flag_implicit_templates
|| (flag_implicit_inline_templates
&& TREE_CODE (decl) == FUNCTION_DECL
&& DECL_DECLARED_INLINE_P (decl)))
comdat_p = true;
else
import_p = true;
}
else if (DECL_FUNCTION_MEMBER_P (decl))
{
if (!DECL_DECLARED_INLINE_P (decl))
{
tree ctype = DECL_CONTEXT (decl);
import_export_class (ctype);
if (CLASSTYPE_INTERFACE_KNOWN (ctype))
{
DECL_NOT_REALLY_EXTERN (decl)
= ! (CLASSTYPE_INTERFACE_ONLY (ctype)
|| (DECL_DECLARED_INLINE_P (decl)
&& ! flag_implement_inlines
&& !DECL_VINDEX (decl)));
if (!DECL_NOT_REALLY_EXTERN (decl))
DECL_EXTERNAL (decl) = 1;
if (DECL_ARTIFICIAL (decl) && flag_weak)
comdat_p = true;
else
maybe_make_one_only (decl);
}
}
else
comdat_p = true;
}
else
comdat_p = true;
if (import_p)
{
DECL_EXTERNAL (decl) = 1;
DECL_NOT_REALLY_EXTERN (decl) = 0;
}
else if (comdat_p)
{
comdat_linkage (decl);
}
DECL_INTERFACE_KNOWN (decl) = 1;
}
tree
build_cleanup (tree decl)
{
tree temp;
tree type = TREE_TYPE (decl);
gcc_assert (!TYPE_HAS_TRIVIAL_DESTRUCTOR (type));
mark_used (decl);
if (TREE_CODE (type) == ARRAY_TYPE)
temp = decl;
else
{
cxx_mark_addressable (decl);
temp = build1 (ADDR_EXPR, build_pointer_type (type), decl);
}
temp = build_delete (TREE_TYPE (temp), temp,
sfk_complete_destructor,
LOOKUP_NORMAL|LOOKUP_NONVIRTUAL|LOOKUP_DESTRUCTOR, 0);
return temp;
}
tree
get_guard (tree decl)
{
tree sname;
tree guard;
sname = mangle_guard_variable (decl);
guard = IDENTIFIER_GLOBAL_VALUE (sname);
if (! guard)
{
tree guard_type;
guard_type = targetm.cxx.guard_type ();
guard = build_decl (VAR_DECL, sname, guard_type);
TREE_PUBLIC (guard) = TREE_PUBLIC (decl);
TREE_STATIC (guard) = TREE_STATIC (decl);
DECL_COMMON (guard) = DECL_COMMON (decl);
DECL_ONE_ONLY (guard) = DECL_ONE_ONLY (decl);
if (TREE_PUBLIC (decl))
DECL_WEAK (guard) = DECL_WEAK (decl);
DECL_ARTIFICIAL (guard) = 1;
DECL_IGNORED_P (guard) = 1;
TREE_USED (guard) = 1;
pushdecl_top_level_and_finish (guard, NULL_TREE);
}
return guard;
}
static tree
get_guard_bits (tree guard)
{
if (!targetm.cxx.guard_mask_bit ())
{
guard = build1 (ADDR_EXPR,
build_pointer_type (TREE_TYPE (guard)),
guard);
guard = build1 (NOP_EXPR,
build_pointer_type (char_type_node),
guard);
guard = build1 (INDIRECT_REF, char_type_node, guard);
}
return guard;
}
tree
get_guard_cond (tree guard)
{
tree guard_value;
guard = get_guard_bits (guard);
if (targetm.cxx.guard_mask_bit ())
{
guard_value = integer_one_node;
if (!same_type_p (TREE_TYPE (guard_value), TREE_TYPE (guard)))
guard_value = convert (TREE_TYPE (guard), guard_value);
guard = cp_build_binary_op (BIT_AND_EXPR, guard, guard_value);
}
guard_value = integer_zero_node;
if (!same_type_p (TREE_TYPE (guard_value), TREE_TYPE (guard)))
guard_value = convert (TREE_TYPE (guard), guard_value);
return cp_build_binary_op (EQ_EXPR, guard, guard_value);
}
tree
set_guard (tree guard)
{
tree guard_init;
guard = get_guard_bits (guard);
guard_init = integer_one_node;
if (!same_type_p (TREE_TYPE (guard_init), TREE_TYPE (guard)))
guard_init = convert (TREE_TYPE (guard), guard_init);
return build_modify_expr (guard, NOP_EXPR, guard_init);
}
static tree
start_objects (int method_type, int initp)
{
tree body;
tree fndecl;
char type[10];
if (initp != DEFAULT_INIT_PRIORITY)
{
char joiner;
#ifdef JOINER
joiner = JOINER;
#else
joiner = '_';
#endif
sprintf (type, "%c%c%.5u", method_type, joiner, initp);
}
else
sprintf (type, "%c", method_type);
fndecl = build_lang_decl (FUNCTION_DECL,
\
get_file_function_name (type),
\
build_function_type (void_type_node,
void_list_node));
start_preparsed_function (fndecl, NULL_TREE, SF_PRE_PARSED);
TREE_PUBLIC (current_function_decl) = ! targetm.have_ctors_dtors;
DECL_ARTIFICIAL (current_function_decl) = 1;
TREE_USED (current_function_decl) = 1;
if (method_type == 'I')
DECL_GLOBAL_CTOR_P (current_function_decl) = 1;
else
DECL_GLOBAL_DTOR_P (current_function_decl) = 1;
DECL_LANG_SPECIFIC (current_function_decl)->decl_flags.u2sel = 1;
#ifdef STATIC_INIT_SECTION
if (!TARGET_KEXTABI)
DECL_SECTION_NAME (current_function_decl) =
build_string (strlen (STATIC_INIT_SECTION), STATIC_INIT_SECTION);
#endif
body = begin_compound_stmt (BCS_FN_BODY);
DECL_INLINE (current_function_decl) = 0;
DECL_UNINLINABLE (current_function_decl) = 1;
return body;
}
static void
finish_objects (int method_type, int initp, tree body)
{
tree fn;
finish_compound_stmt (body);
fn = finish_function (0);
expand_or_defer_fn (fn);
if (flag_syntax_only)
return;
if (targetm.have_ctors_dtors)
{
rtx fnsym = XEXP (DECL_RTL (fn), 0);
cgraph_mark_needed_node (cgraph_node (fn));
if (method_type == 'I')
(* targetm.asm_out.constructor) (fnsym, initp);
else
(* targetm.asm_out.destructor) (fnsym, initp);
}
}
#define INITIALIZE_P_IDENTIFIER "__initialize_p"
#define PRIORITY_IDENTIFIER "__priority"
#define SSDF_IDENTIFIER "__static_initialization_and_destruction"
static GTY(()) tree initialize_p_decl;
static GTY(()) tree priority_decl;
static GTY(()) tree ssdf_decl;
static GTY(()) VEC(tree,gc) *ssdf_decls;
static splay_tree priority_info_map;
static tree
start_static_storage_duration_function (unsigned count)
{
tree parm_types;
tree type;
tree body;
char id[sizeof (SSDF_IDENTIFIER) + 1 + 32];
sprintf (id, "%s_%u", SSDF_IDENTIFIER, count);
parm_types = void_list_node;
parm_types = tree_cons (NULL_TREE, integer_type_node, parm_types);
parm_types = tree_cons (NULL_TREE, integer_type_node, parm_types);
type = build_function_type (void_type_node, parm_types);
ssdf_decl = build_lang_decl (FUNCTION_DECL,
get_identifier (id),
type);
TREE_PUBLIC (ssdf_decl) = 0;
DECL_ARTIFICIAL (ssdf_decl) = 1;
#ifdef STATIC_INIT_SECTION
if (!TARGET_KEXTABI)
DECL_SECTION_NAME (ssdf_decl) = build_string (strlen (STATIC_INIT_SECTION),
STATIC_INIT_SECTION);
#endif
if (!ssdf_decls)
{
ssdf_decls = VEC_alloc (tree, gc, 32);
priority_info_map = splay_tree_new (splay_tree_compare_ints,
0,
(splay_tree_delete_value_fn) &free);
get_priority_info (DEFAULT_INIT_PRIORITY);
}
VEC_safe_push (tree, gc, ssdf_decls, ssdf_decl);
initialize_p_decl = cp_build_parm_decl
(get_identifier (INITIALIZE_P_IDENTIFIER), integer_type_node);
DECL_CONTEXT (initialize_p_decl) = ssdf_decl;
TREE_USED (initialize_p_decl) = 1;
priority_decl = cp_build_parm_decl
(get_identifier (PRIORITY_IDENTIFIER), integer_type_node);
DECL_CONTEXT (priority_decl) = ssdf_decl;
TREE_USED (priority_decl) = 1;
TREE_CHAIN (initialize_p_decl) = priority_decl;
DECL_ARGUMENTS (ssdf_decl) = initialize_p_decl;
pushdecl (ssdf_decl);
start_preparsed_function (ssdf_decl,
NULL_TREE,
SF_PRE_PARSED);
body = begin_compound_stmt (BCS_FN_BODY);
DECL_INLINE (ssdf_decl) = 0;
DECL_UNINLINABLE (ssdf_decl) = 1;
return body;
}
static void
finish_static_storage_duration_function (tree body)
{
finish_compound_stmt (body);
expand_or_defer_fn (finish_function (0));
}
static priority_info
get_priority_info (int priority)
{
priority_info pi;
splay_tree_node n;
n = splay_tree_lookup (priority_info_map,
(splay_tree_key) priority);
if (!n)
{
pi = XNEW (struct priority_info_s);
pi->initializations_p = 0;
pi->destructions_p = 0;
splay_tree_insert (priority_info_map,
(splay_tree_key) priority,
(splay_tree_value) pi);
}
else
pi = (priority_info) n->value;
return pi;
}
#define DECL_EFFECTIVE_INIT_PRIORITY(decl) \
((!DECL_HAS_INIT_PRIORITY_P (decl) || DECL_INIT_PRIORITY (decl) == 0) \
? DEFAULT_INIT_PRIORITY : DECL_INIT_PRIORITY (decl))
#define NEEDS_GUARD_P(decl) (TREE_PUBLIC (decl) && (DECL_COMMON (decl) \
|| DECL_ONE_ONLY (decl) \
|| DECL_WEAK (decl) \
|| (TARGET_WEAK_NOT_IN_ARCHIVE_TOC && DECL_LANG_SPECIFIC (decl) \
&& (DECL_EXPLICIT_INSTANTIATION (decl) \
|| DECL_TEMPLATE_SPECIALIZATION (decl)))))
static bool
does_nothing_p (tree exp)
{
tree_stmt_iterator i;
if (exp == NULL_TREE)
return true;
if (TREE_CODE (exp) == STATEMENT_LIST)
{
for (i = tsi_start (exp); !tsi_end_p (i); tsi_next (&i))
{
if (!does_nothing_p (*tsi_stmt_ptr (i)))
return false;
}
return true;
}
else if (TREE_CODE (exp) == CALL_EXPR)
{
tree decl = NULL_TREE;
if (TREE_CODE (TREE_OPERAND (exp, 0)) == ADDR_EXPR
&& (TREE_CODE (decl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0))
== FUNCTION_DECL))
{
if (TREE_OPERAND (exp, 1))
{
if (TREE_CODE (TREE_OPERAND (exp, 1)) != TREE_LIST)
return false;
if (TREE_CHAIN (TREE_OPERAND (exp, 1)))
return false;
if (TREE_SIDE_EFFECTS (TREE_VALUE (TREE_OPERAND (exp, 1))))
return false;
}
if (DECL_UNINLINABLE (decl))
return false;
if (!((flag_inline_trees || !flag_no_inline) && !flag_really_no_inline)
&& !lookup_attribute ("always_inline", DECL_ATTRIBUTES (decl)))
return false;
exp = DECL_SAVED_TREE (decl);
if (!exp)
return false;
return does_nothing_p (exp);
}
return false;
}
else if (TREE_CODE (exp) == EXPR_STMT)
return does_nothing_p (TREE_OPERAND (exp, 0));
else if (TREE_CODE (exp) == BIND_EXPR)
return does_nothing_p (BIND_EXPR_BODY (exp));
else if (TREE_CODE (exp) == MODIFY_EXPR)
{
bool was_set_zero = (integer_zerop (TREE_OPERAND (exp, 1))
|| real_zerop (TREE_OPERAND (exp, 1)));
if (TREE_SIDE_EFFECTS (TREE_OPERAND (exp, 1)))
return false;
exp = TREE_OPERAND (exp, 0);
if (TREE_SIDE_EFFECTS (exp))
return false;
if (TREE_CODE (exp) != VAR_DECL)
{
if (was_set_zero
&& TREE_CODE (exp) == COMPONENT_REF
&& !TREE_SIDE_EFFECTS (exp)
&& TREE_CODE (TREE_OPERAND (exp, 1)) == FIELD_DECL
&& TREE_CODE (exp=TREE_OPERAND (exp, 0)) == INDIRECT_REF
&& TREE_CODE (exp=TREE_OPERAND (exp, 0)) == PARM_DECL
&& DECL_NAME (exp) == this_identifier)
return true;
return false;
}
if (TREE_STATIC (exp))
return false;
return true;
}
else if (TREE_CODE (exp) == COND_EXPR)
{
tree cond = TREE_OPERAND (exp, 0);
cond = fold (cond);
if (integer_onep (cond))
return does_nothing_p (TREE_OPERAND (exp, 1));
else if (integer_zerop (cond))
return does_nothing_p (TREE_OPERAND (exp, 2));
}
else if (TREE_CODE (exp) == TRY_CATCH_EXPR)
return does_nothing_p (TREE_OPERAND (exp, 0));
return false;
}
static void
warn_init (tree decl)
{
warning (OPT_Wglobal_constructors, "%J%qD requires global construction", decl, decl);
}
static void
warn_deinit (tree decl)
{
warning (OPT_Wglobal_constructors, "%J%qD requires global destruction", decl, decl);
}
static void
one_static_initialization_or_destruction (tree decl, tree init, bool initp,
priority_info pi)
{
tree guard_if_stmt = NULL_TREE;
tree guard;
if (!initp
&& TYPE_HAS_TRIVIAL_DESTRUCTOR (TREE_TYPE (decl)))
return;
input_location = DECL_SOURCE_LOCATION (decl);
if (member_p (decl))
{
DECL_CONTEXT (current_function_decl) = DECL_CONTEXT (decl);
DECL_STATIC_FUNCTION_P (current_function_decl) = 1;
}
guard = NULL_TREE;
if (NEEDS_GUARD_P (decl))
{
tree guard_cond;
guard = get_guard (decl);
if (initp)
{
pi->initializations_p = 1;
warn_init (decl);
}
else
{
pi->destructions_p = 1;
warn_deinit (decl);
}
if (flag_use_cxa_atexit)
{
gcc_assert (initp);
guard_cond = get_guard_cond (guard);
}
else if (initp)
guard_cond
= cp_build_binary_op (EQ_EXPR,
build_unary_op (PREINCREMENT_EXPR,
guard,
1),
integer_one_node);
else
guard_cond
= cp_build_binary_op (EQ_EXPR,
build_unary_op (PREDECREMENT_EXPR,
guard,
1),
integer_zero_node);
guard_if_stmt = begin_if_stmt ();
finish_if_stmt_cond (guard_cond, guard_if_stmt);
}
if (guard && initp && flag_use_cxa_atexit)
finish_expr_stmt (set_guard (guard));
if (initp)
{
if (init)
{
if (!does_nothing_p (init))
{
pi->initializations_p = 1;
if (!guard) warn_init (decl);
finish_expr_stmt (init);
}
}
if (flag_use_cxa_atexit)
{
pi->initializations_p = 1;
if (!guard
&& !TYPE_HAS_TRIVIAL_DESTRUCTOR (TREE_TYPE (decl)))
warn_deinit (decl);
finish_expr_stmt (register_dtor_fn (decl));
}
}
else
{
pi->destructions_p = 1;
if (!guard) warn_deinit (decl);
finish_expr_stmt (build_cleanup (decl));
}
if (guard)
{
finish_then_clause (guard_if_stmt);
finish_if_stmt (guard_if_stmt);
}
DECL_CONTEXT (current_function_decl) = NULL_TREE;
DECL_STATIC_FUNCTION_P (current_function_decl) = 0;
}
static void
do_static_initialization_or_destruction (tree vars, bool initp)
{
tree node, init_if_stmt, cond;
init_if_stmt = begin_if_stmt ();
cond = initp ? integer_one_node : integer_zero_node;
cond = cp_build_binary_op (EQ_EXPR,
initialize_p_decl,
cond);
finish_if_stmt_cond (cond, init_if_stmt);
node = vars;
do {
tree decl = TREE_VALUE (node);
tree priority_if_stmt;
int priority;
priority_info pi;
if (!initp && TYPE_HAS_TRIVIAL_DESTRUCTOR (TREE_TYPE (decl)))
{
node = TREE_CHAIN (node);
continue;
}
priority = DECL_EFFECTIVE_INIT_PRIORITY (decl);
pi = get_priority_info (priority);
priority_if_stmt = begin_if_stmt ();
cond = cp_build_binary_op (EQ_EXPR,
priority_decl,
build_int_cst (NULL_TREE, priority));
finish_if_stmt_cond (cond, priority_if_stmt);
for (; node
&& DECL_EFFECTIVE_INIT_PRIORITY (TREE_VALUE (node)) == priority;
node = TREE_CHAIN (node))
one_static_initialization_or_destruction (TREE_VALUE (node),
TREE_PURPOSE (node), initp, pi);
finish_then_clause (priority_if_stmt);
finish_if_stmt (priority_if_stmt);
} while (node);
finish_then_clause (init_if_stmt);
finish_if_stmt (init_if_stmt);
}
static tree
prune_vars_needing_no_initialization (tree *vars)
{
tree *var = vars;
tree result = NULL_TREE;
while (*var)
{
tree t = *var;
tree decl = TREE_VALUE (t);
tree init = TREE_PURPOSE (t);
if (decl == error_mark_node)
{
var = &TREE_CHAIN (t);
continue;
}
gcc_assert (TREE_CODE (decl) == VAR_DECL);
if (DECL_EXTERNAL (decl))
{
var = &TREE_CHAIN (t);
continue;
}
if (init && TREE_CODE (init) == TREE_LIST
&& value_member (error_mark_node, init))
{
var = &TREE_CHAIN (t);
continue;
}
if (init
&& does_nothing_p (init)
&& TYPE_HAS_TRIVIAL_DESTRUCTOR (TREE_TYPE (decl))
&& !NEEDS_GUARD_P (decl))
{
var = &TREE_CHAIN (t);
continue;
}
*var = TREE_CHAIN (t);
TREE_CHAIN (t) = result;
result = t;
}
return result;
}
static void
write_out_vars (tree vars)
{
tree v;
for (v = vars; v; v = TREE_CHAIN (v))
{
tree var = TREE_VALUE (v);
if (!var_finalized_p (var))
{
import_export_decl (var);
rest_of_decl_compilation (var, 1, 1);
}
}
}
static void
generate_ctor_or_dtor_function (bool constructor_p, int priority,
location_t *locus)
{
char function_key;
tree arguments;
tree fndecl;
tree body;
size_t i;
input_location = *locus;
#ifdef USE_MAPPED_LOCATION
#else
locus->line++;
#endif
function_key = constructor_p ? 'I' : 'D';
body = NULL_TREE;
if (c_dialect_objc () && (priority == DEFAULT_INIT_PRIORITY)
&& constructor_p && objc_static_init_needed_p ())
{
body = start_objects (function_key, priority);
static_ctors = objc_generate_static_init_call (static_ctors);
warning (OPT_Wglobal_constructors,
"GNU Objective-C runtime requires global initialization");
}
for (i = 0; VEC_iterate (tree, ssdf_decls, i, fndecl); ++i)
{
if (! (flags_from_decl_or_type (fndecl) & (ECF_CONST | ECF_PURE)))
{
if (! body)
body = start_objects (function_key, priority);
arguments = tree_cons (NULL_TREE,
build_int_cst (NULL_TREE, priority),
NULL_TREE);
arguments = tree_cons (NULL_TREE,
build_int_cst (NULL_TREE, constructor_p),
arguments);
finish_expr_stmt (build_function_call (fndecl, arguments));
}
}
if (priority == DEFAULT_INIT_PRIORITY)
{
tree fns;
for (fns = constructor_p ? static_ctors : static_dtors;
fns;
fns = TREE_CHAIN (fns))
{
fndecl = TREE_VALUE (fns);
if (constructor_p)
warn_init (fndecl);
else
warn_deinit (fndecl);
if (! (flags_from_decl_or_type (fndecl) & (ECF_CONST | ECF_PURE)))
{
if (! body)
body = start_objects (function_key, priority);
finish_expr_stmt (build_function_call (fndecl, NULL_TREE));
}
}
}
if (body)
finish_objects (function_key, priority, body);
}
static int
generate_ctor_and_dtor_functions_for_priority (splay_tree_node n, void * data)
{
location_t *locus = (location_t *) data;
int priority = (int) n->key;
priority_info pi = (priority_info) n->value;
if (pi->initializations_p
|| (priority == DEFAULT_INIT_PRIORITY && static_ctors))
generate_ctor_or_dtor_function (true, priority, locus);
if (pi->destructions_p
|| (priority == DEFAULT_INIT_PRIORITY && static_dtors))
generate_ctor_or_dtor_function (false, priority, locus);
return 0;
}
tree
cxx_callgraph_analyze_expr (tree *tp, int *walk_subtrees ATTRIBUTE_UNUSED,
tree from ATTRIBUTE_UNUSED)
{
tree t = *tp;
switch (TREE_CODE (t))
{
case PTRMEM_CST:
if (TYPE_PTRMEMFUNC_P (TREE_TYPE (t)))
cgraph_mark_needed_node (cgraph_node (PTRMEM_CST_MEMBER (t)));
break;
case BASELINK:
if (TREE_CODE (BASELINK_FUNCTIONS (t)) == FUNCTION_DECL)
cgraph_mark_needed_node (cgraph_node (BASELINK_FUNCTIONS (t)));
break;
case VAR_DECL:
if (DECL_VTABLE_OR_VTT_P (t))
{
tree vtbl;
for (vtbl = CLASSTYPE_VTABLES (DECL_CONTEXT (t));
vtbl;
vtbl = TREE_CHAIN (vtbl))
mark_decl_referenced (vtbl);
}
else if (DECL_CONTEXT (t)
&& TREE_CODE (DECL_CONTEXT (t)) == FUNCTION_DECL)
mark_decl_referenced (DECL_CONTEXT (t));
break;
default:
break;
}
return NULL;
}
static void
build_java_method_aliases (void)
{
struct cgraph_node *node;
#ifndef HAVE_GAS_HIDDEN
return;
#endif
for (node = cgraph_nodes; node ; node = node->next)
{
tree fndecl = node->decl;
if (TREE_ASM_WRITTEN (fndecl)
&& DECL_CONTEXT (fndecl)
&& TYPE_P (DECL_CONTEXT (fndecl))
&& TYPE_FOR_JAVA (DECL_CONTEXT (fndecl))
&& TARGET_USE_LOCAL_THUNK_ALIAS_P (fndecl))
{
tree oid, nid, alias;
const char *oname;
char *nname;
oid = DECL_ASSEMBLER_NAME (fndecl);
oname = IDENTIFIER_POINTER (oid);
gcc_assert (oname[0] == '_' && oname[1] == 'Z');
nname = ACONCAT (("_ZGA", oname+2, NULL));
nid = get_identifier (nname);
alias = make_alias_for (fndecl, nid);
TREE_PUBLIC (alias) = 1;
DECL_VISIBILITY (alias) = VISIBILITY_HIDDEN;
assemble_alias (alias, oid);
}
}
}
static void emit_deferred (location_t *);
void
cp_finish_file (void)
{
location_t locus;
locus = input_location;
at_eof = 1;
if (! global_bindings_p () || current_class_type || decl_namespace_list)
return;
#ifdef USE_MAPPED_LOCATION
#else
input_line -= 1;
#endif
timevar_push (TV_VARCONST);
emit_support_tinfos ();
emit_instantiate_pending_templates (&locus);
emit_deferred (&locus);
}
void
emit_instantiate_pending_templates (location_t *locusp)
{
tree vars;
bool reconsider;
size_t i;
unsigned ssdf_count = 0;
int retries = 0;
at_eof = 1;
do
{
tree t;
tree decl;
reconsider = false;
instantiate_pending_templates (retries);
ggc_collect ();
while (keyed_classes != NULL_TREE
&& maybe_emit_vtables (TREE_VALUE (keyed_classes)))
{
reconsider = true;
keyed_classes = TREE_CHAIN (keyed_classes);
}
t = keyed_classes;
if (t != NULL_TREE)
{
tree next = TREE_CHAIN (t);
while (next)
{
if (maybe_emit_vtables (TREE_VALUE (next)))
{
reconsider = true;
TREE_CHAIN (t) = TREE_CHAIN (next);
}
else
t = next;
next = TREE_CHAIN (t);
}
}
for (i = VEC_length (tree, unemitted_tinfo_decls);
VEC_iterate (tree, unemitted_tinfo_decls, --i, t);)
if (emit_tinfo_decl (t))
{
reconsider = true;
VEC_unordered_remove (tree, unemitted_tinfo_decls, i);
}
vars = prune_vars_needing_no_initialization (&static_aggregates);
if (vars)
{
tree ssdf_body;
input_location = *locusp;
ssdf_body = start_static_storage_duration_function (ssdf_count);
write_out_vars (vars);
if (vars)
do_static_initialization_or_destruction (vars, true);
if (!flag_use_cxa_atexit && vars)
{
vars = nreverse (vars);
do_static_initialization_or_destruction (vars, false);
}
else
vars = NULL_TREE;
input_location = *locusp;
finish_static_storage_duration_function (ssdf_body);
reconsider = true;
ssdf_count++;
#ifdef USE_MAPPED_LOCATION
#else
locusp->line++;
#endif
}
for (i = 0; VEC_iterate (tree, deferred_fns, i, decl); ++i)
{
if (DECL_ARTIFICIAL (decl) && ! DECL_INITIAL (decl)
&& (! DECL_REALLY_EXTERN (decl) || DECL_INLINE (decl)))
{
push_to_top_level ();
input_location = DECL_SOURCE_LOCATION (decl);
synthesize_method (decl);
pop_from_top_level ();
reconsider = true;
}
if (!DECL_SAVED_TREE (decl))
continue;
import_export_decl (decl);
if (DECL_NOT_REALLY_EXTERN (decl)
&& DECL_INITIAL (decl)
&& decl_needed_p (decl))
DECL_EXTERNAL (decl) = 0;
if (!DECL_EXTERNAL (decl)
&& decl_needed_p (decl)
&& !TREE_ASM_WRITTEN (decl)
&& !cgraph_node (decl)->local.finalized)
{
DECL_DEFER_OUTPUT (decl) = 0;
expand_or_defer_fn (decl);
if (flag_syntax_only)
TREE_ASM_WRITTEN (decl) = 1;
reconsider = true;
}
}
if (walk_namespaces (wrapup_globals_for_namespace, 0))
reconsider = true;
for (i = 0; VEC_iterate (tree, pending_statics, i, decl); ++i)
{
if (var_finalized_p (decl) || DECL_REALLY_EXTERN (decl))
continue;
import_export_decl (decl);
if (DECL_NOT_REALLY_EXTERN (decl) && decl_needed_p (decl))
DECL_EXTERNAL (decl) = 0;
#ifdef MACHOPIC_VAR_REFERRED_TO_P
else
if (TREE_USED (decl) && DECL_INITIAL (decl) != 0
&& DECL_INITIAL (decl) != error_mark_node
&& TREE_CODE (DECL_INITIAL (decl)) != CONSTRUCTOR
&& DECL_EXTERNAL (decl)
&& MACHOPIC_VAR_REFERRED_TO_P (IDENTIFIER_POINTER (
DECL_ASSEMBLER_NAME (decl))))
{
DECL_EXTERNAL (decl) = 0;
TREE_PUBLIC (decl) = 0;
}
#endif
}
if (VEC_length (tree, pending_statics) != 0
&& wrapup_global_declarations (VEC_address (tree, pending_statics),
VEC_length (tree, pending_statics)))
reconsider = true;
retries++;
}
while (reconsider);
}
static void
emit_deferred (location_t *locusp)
{
size_t i;
tree decl;
bool reconsider = false;
for (i = 0; VEC_iterate (tree, deferred_fns, i, decl); ++i)
{
if (
TREE_USED (decl) && DECL_DECLARED_INLINE_P (decl)
&& !DECL_INITIAL (decl)
&& !DECL_EXPLICIT_INSTANTIATION (decl))
{
warning (0, "inline function %q+D used but never defined", decl);
TREE_NO_WARNING (decl) = 1;
}
}
push_lang_context (lang_name_c);
if (priority_info_map)
splay_tree_foreach (priority_info_map,
generate_ctor_and_dtor_functions_for_priority,
locusp);
else
{
if (static_ctors || (c_dialect_objc () && objc_static_init_needed_p ()))
generate_ctor_or_dtor_function (true,
DEFAULT_INIT_PRIORITY, locusp);
if (static_dtors)
generate_ctor_or_dtor_function (false,
DEFAULT_INIT_PRIORITY, locusp);
}
if (priority_info_map)
splay_tree_delete (priority_info_map);
maybe_apply_pending_pragma_weaks ();
pop_lang_context ();
cgraph_finalize_compilation_unit ();
cgraph_optimize ();
walk_namespaces (wrapup_globals_for_namespace, &reconsider);
if (VEC_length (tree, pending_statics) != 0)
{
check_global_declarations (VEC_address (tree, pending_statics),
VEC_length (tree, pending_statics));
emit_debug_global_declarations (VEC_address (tree, pending_statics),
VEC_length (tree, pending_statics));
}
build_java_method_aliases ();
finish_repo ();
{
int flags;
FILE *stream = dump_begin (TDI_tu, &flags);
if (stream)
{
dump_node (global_namespace, flags & ~TDF_SLIM, stream);
dump_end (TDI_tu, stream);
}
}
timevar_pop (TV_VARCONST);
if (flag_detailed_statistics)
{
dump_tree_statistics ();
dump_time_statistics ();
}
input_location = *locusp;
#ifdef ENABLE_CHECKING
validate_conversion_obstack ();
#endif
}
tree
build_offset_ref_call_from_tree (tree fn, tree args)
{
tree orig_fn;
tree orig_args;
tree expr;
tree object;
orig_fn = fn;
orig_args = args;
object = TREE_OPERAND (fn, 0);
if (processing_template_decl)
{
gcc_assert (TREE_CODE (fn) == DOTSTAR_EXPR
|| TREE_CODE (fn) == MEMBER_REF);
if (type_dependent_expression_p (fn)
|| any_type_dependent_arguments_p (args))
return build_min_nt (CALL_EXPR, fn, args, NULL_TREE);
args = build_non_dependent_args (args);
if (TREE_CODE (fn) == DOTSTAR_EXPR)
object = build_unary_op (ADDR_EXPR, object, 0);
object = build_non_dependent_expr (object);
args = tree_cons (NULL_TREE, object, args);
fn = build_non_dependent_expr (fn);
}
if (TREE_CODE (fn) == OFFSET_REF)
{
tree object_addr = build_unary_op (ADDR_EXPR, object, 0);
fn = TREE_OPERAND (fn, 1);
fn = get_member_function_from_ptrfunc (&object_addr, fn);
args = tree_cons (NULL_TREE, object_addr, args);
}
expr = build_function_call (fn, args);
if (processing_template_decl && expr != error_mark_node)
return build_min_non_dep (CALL_EXPR, expr, orig_fn, orig_args, NULL_TREE);
return expr;
}
void
check_default_args (tree x)
{
tree arg = TYPE_ARG_TYPES (TREE_TYPE (x));
bool saw_def = false;
int i = 0 - (TREE_CODE (TREE_TYPE (x)) == METHOD_TYPE);
for (; arg && arg != void_list_node; arg = TREE_CHAIN (arg), ++i)
{
if (TREE_PURPOSE (arg))
saw_def = true;
else if (saw_def)
{
error ("default argument missing for parameter %P of %q+#D", i, x);
TREE_PURPOSE (arg) = error_mark_node;
}
}
}
void
mark_used (tree decl)
{
HOST_WIDE_INT saved_processing_template_decl = 0;
if (TREE_CODE (decl) == BASELINK)
{
decl = BASELINK_FUNCTIONS (decl);
if (really_overloaded_fn (decl))
return;
decl = OVL_CURRENT (decl);
}
TREE_USED (decl) = 1;
if (DECL_CLONED_FUNCTION_P (decl))
TREE_USED (DECL_CLONED_FUNCTION (decl)) = 1;
if (skip_evaluation)
return;
if (TREE_CODE (decl) == VAR_DECL
&& DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (decl)
&& DECL_CLASS_SCOPE_P (decl))
{
if (CLASSTYPE_TEMPLATE_INFO ((DECL_CONTEXT (decl)))
&& uses_template_parms (CLASSTYPE_TI_ARGS (DECL_CONTEXT (decl))))
return;
saved_processing_template_decl = processing_template_decl;
processing_template_decl = 0;
}
if (processing_template_decl)
return;
if (TREE_CODE (decl) == FUNCTION_DECL && DECL_DECLARED_INLINE_P (decl)
&& !TREE_ASM_WRITTEN (decl))
{
if (DECL_DEFERRED_FN (decl))
return;
if (DECL_ARTIFICIAL (decl) && DECL_NONSTATIC_MEMBER_FUNCTION_P (decl)
&& !DECL_THUNK_P (decl))
DECL_SOURCE_LOCATION (decl) = input_location;
note_vague_linkage_fn (decl);
}
assemble_external (decl);
if (TREE_CODE (decl) == FUNCTION_DECL
&& DECL_NONSTATIC_MEMBER_FUNCTION_P (decl)
&& DECL_ARTIFICIAL (decl)
&& !DECL_THUNK_P (decl)
&& ! DECL_INITIAL (decl)
&& current_function_decl)
{
synthesize_method (decl);
}
else if ((DECL_NON_THUNK_FUNCTION_P (decl) || TREE_CODE (decl) == VAR_DECL)
&& DECL_LANG_SPECIFIC (decl) && DECL_TEMPLATE_INFO (decl)
&& (!DECL_EXPLICIT_INSTANTIATION (decl)
|| (TREE_CODE (decl) == FUNCTION_DECL
&& DECL_INLINE (DECL_TEMPLATE_RESULT
(template_for_substitution (decl))))
|| (TREE_CODE (decl) == VAR_DECL
&& DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (decl))))
instantiate_decl (decl, true,
false);
processing_template_decl = saved_processing_template_decl;
}
#include "gt-cp-decl2.h"