static GTY ((if_marked ("tree_int_map_marked_p"), param_is (struct tree_int_map)))
htab_t init_priority_for_decl;
+static GTY ((if_marked ("tree_map_marked_p"), param_is (struct tree_map)))
+ htab_t restrict_base_for_decl;
+
struct tree_int_map GTY(())
{
tree from;
tree_map_eq, 0);
init_priority_for_decl = htab_create_ggc (512, tree_int_map_hash,
tree_int_map_eq, 0);
+ restrict_base_for_decl = htab_create_ggc (256, tree_map_hash,
+ tree_map_eq, 0);
int_cst_hash_table = htab_create_ggc (1024, int_cst_hash_hash,
int_cst_hash_eq, NULL);
SET_DECL_INIT_PRIORITY (t, DECL_INIT_PRIORITY (node));
DECL_HAS_INIT_PRIORITY_P (t) = 1;
}
-
+ if (TREE_CODE (node) == VAR_DECL && DECL_BASED_ON_RESTRICT_P (node))
+ {
+ SET_DECL_RESTRICT_BASE (t, DECL_GET_RESTRICT_BASE (node));
+ DECL_BASED_ON_RESTRICT_P (t) = 1;
+ }
}
else if (TREE_CODE_CLASS (code) == tcc_type)
{
case VAR_DECL:
return ((TREE_STATIC (arg) || DECL_EXTERNAL (arg))
&& ! DECL_THREAD_LOCAL_P (arg)
- && ! DECL_NON_ADDR_CONST_P (arg)
+ && ! DECL_DLLIMPORT_P (arg)
? arg : NULL);
case CONST_DECL:
substitute_in_expr (tree exp, tree f, tree r)
{
enum tree_code code = TREE_CODE (exp);
- tree op0, op1, op2;
+ tree op0, op1, op2, op3;
tree new;
tree inner;
new = fold_build3 (code, TREE_TYPE (exp), op0, op1, op2);
break;
+ case 4:
+ op0 = SUBSTITUTE_IN_EXPR (TREE_OPERAND (exp, 0), f, r);
+ op1 = SUBSTITUTE_IN_EXPR (TREE_OPERAND (exp, 1), f, r);
+ op2 = SUBSTITUTE_IN_EXPR (TREE_OPERAND (exp, 2), f, r);
+ op3 = SUBSTITUTE_IN_EXPR (TREE_OPERAND (exp, 3), f, r);
+
+ if (op0 == TREE_OPERAND (exp, 0) && op1 == TREE_OPERAND (exp, 1)
+ && op2 == TREE_OPERAND (exp, 2)
+ && op3 == TREE_OPERAND (exp, 3))
+ return exp;
+
+ new = fold (build4 (code, TREE_TYPE (exp), op0, op1, op2, op3));
+ break;
+
default:
gcc_unreachable ();
}
#if 1 /* ! defined(USE_MAPPED_LOCATION) */
/* ??? gengtype doesn't handle conditionals */
-static GTY(()) tree last_annotated_node;
+static GTY(()) location_t *last_annotated_node;
#endif
#ifdef USE_MAPPED_LOCATION
a node with the same information already attached to that node!
Just return instead of wasting memory. */
if (EXPR_LOCUS (node)
+ && EXPR_LINENO (node) == line
&& (EXPR_FILENAME (node) == file
- || ! strcmp (EXPR_FILENAME (node), file))
- && EXPR_LINENO (node) == line)
+ || !strcmp (EXPR_FILENAME (node), file)))
{
- last_annotated_node = node;
+ last_annotated_node = EXPR_LOCUS (node);
return;
}
entry cache can reduce the number of allocations by more
than half. */
if (last_annotated_node
- && EXPR_LOCUS (last_annotated_node)
- && (EXPR_FILENAME (last_annotated_node) == file
- || ! strcmp (EXPR_FILENAME (last_annotated_node), file))
- && EXPR_LINENO (last_annotated_node) == line)
+ && last_annotated_node->line == line
+ && (last_annotated_node->file == file
+ || !strcmp (last_annotated_node->file, file)))
{
- SET_EXPR_LOCUS (node, EXPR_LOCUS (last_annotated_node));
+ SET_EXPR_LOCUS (node, last_annotated_node);
return;
}
SET_EXPR_LOCUS (node, ggc_alloc (sizeof (location_t)));
EXPR_LINENO (node) = line;
EXPR_FILENAME (node) = file;
- last_annotated_node = node;
+ last_annotated_node = EXPR_LOCUS (node);
}
void
merge_dllimport_decl_attributes (tree old, tree new)
{
tree a;
- int delete_dllimport_p;
-
- old = DECL_ATTRIBUTES (old);
- new = DECL_ATTRIBUTES (new);
+ int delete_dllimport_p = 1;
/* What we need to do here is remove from `old' dllimport if it doesn't
appear in `new'. dllimport behaves like extern: if a declaration is
marked dllimport and a definition appears later, then the object
- is not dllimport'd. */
- if (lookup_attribute ("dllimport", old) != NULL_TREE
- && lookup_attribute ("dllimport", new) == NULL_TREE)
- delete_dllimport_p = 1;
+ is not dllimport'd. We also remove a `new' dllimport if the old list
+ contains dllexport: dllexport always overrides dllimport, regardless
+ of the order of declaration. */
+ if (!VAR_OR_FUNCTION_DECL_P (new))
+ delete_dllimport_p = 0;
+ else if (DECL_DLLIMPORT_P (new)
+ && lookup_attribute ("dllexport", DECL_ATTRIBUTES (old)))
+ {
+ DECL_DLLIMPORT_P (new) = 0;
+ warning (OPT_Wattributes, "%q+D already declared with dllexport attribute: "
+ "dllimport ignored", new);
+ }
+ else if (DECL_DLLIMPORT_P (old) && !DECL_DLLIMPORT_P (new))
+ {
+ /* Warn about overriding a symbol that has already been used. eg:
+ extern int __attribute__ ((dllimport)) foo;
+ int* bar () {return &foo;}
+ int foo;
+ */
+ if (TREE_USED (old))
+ {
+ warning (0, "%q+D redeclared without dllimport attribute "
+ "after being referenced with dll linkage", new);
+ /* If we have used a variable's address with dllimport linkage,
+ keep the old DECL_DLLIMPORT_P flag: the ADDR_EXPR using the
+ decl may already have had TREE_INVARIANT and TREE_CONSTANT
+ computed.
+ We still remove the attribute so that assembler code refers
+ to '&foo rather than '_imp__foo'. */
+ if (TREE_CODE (old) == VAR_DECL && TREE_ADDRESSABLE (old))
+ DECL_DLLIMPORT_P (new) = 1;
+ }
+
+ /* Let an inline definition silently override the external reference,
+ but otherwise warn about attribute inconsistency. */
+ else if (TREE_CODE (new) == VAR_DECL
+ || !DECL_DECLARED_INLINE_P (new))
+ warning (OPT_Wattributes, "%q+D redeclared without dllimport attribute: "
+ "previous dllimport ignored", new);
+ }
else
delete_dllimport_p = 0;
- a = merge_attributes (old, new);
+ a = merge_attributes (DECL_ATTRIBUTES (old), DECL_ATTRIBUTES (new));
- if (delete_dllimport_p)
+ if (delete_dllimport_p)
{
tree prev, t;
-
+ const size_t attr_len = strlen ("dllimport");
+
/* Scan the list for dllimport and delete it. */
for (prev = NULL_TREE, t = a; t; prev = t, t = TREE_CHAIN (t))
{
- if (is_attribute_p ("dllimport", TREE_PURPOSE (t)))
+ if (is_attribute_with_length_p ("dllimport", attr_len,
+ TREE_PURPOSE (t)))
{
if (prev == NULL_TREE)
a = TREE_CHAIN (a);
any damage. */
if (is_attribute_p ("dllimport", name))
{
+ /* Honor any target-specific overides. */
+ if (!targetm.valid_dllimport_attribute_p (node))
+ *no_add_attrs = true;
+
+ else if (TREE_CODE (node) == FUNCTION_DECL
+ && DECL_DECLARED_INLINE_P (node))
+ {
+ warning (OPT_Wattributes, "inline function %q+D declared as "
+ " dllimport: attribute ignored", node);
+ *no_add_attrs = true;
+ }
/* Like MS, treat definition of dllimported variables and
- non-inlined functions on declaration as syntax errors. We
- allow the attribute for function definitions if declared
- inline. */
- if (TREE_CODE (node) == FUNCTION_DECL && DECL_INITIAL (node)
- && !DECL_DECLARED_INLINE_P (node))
+ non-inlined functions on declaration as syntax errors. */
+ else if (TREE_CODE (node) == FUNCTION_DECL && DECL_INITIAL (node))
{
error ("function %q+D definition is marked dllimport", node);
*no_add_attrs = true;
}
- else if (TREE_CODE (node) == VAR_DECL)
+ else if (TREE_CODE (node) == VAR_DECL)
{
if (DECL_INITIAL (node))
{
if (current_function_decl != NULL_TREE && !TREE_STATIC (node))
TREE_PUBLIC (node) = 1;
}
+
+ if (*no_add_attrs == false)
+ DECL_DLLIMPORT_P (node) = 1;
}
/* Report error if symbol is not accessible at global scope. */
*(struct tree_int_map **) loc = h;
}
+/* Look up a restrict qualified base decl for FROM. */
+
+tree
+decl_restrict_base_lookup (tree from)
+{
+ struct tree_map *h;
+ struct tree_map in;
+
+ in.from = from;
+ h = htab_find_with_hash (restrict_base_for_decl, &in,
+ htab_hash_pointer (from));
+ return h ? h->to : NULL_TREE;
+}
+
+/* Record the restrict qualified base TO for FROM. */
+
+void
+decl_restrict_base_insert (tree from, tree to)
+{
+ struct tree_map *h;
+ void **loc;
+
+ h = ggc_alloc (sizeof (struct tree_map));
+ h->hash = htab_hash_pointer (from);
+ h->from = from;
+ h->to = to;
+ loc = htab_find_slot_with_hash (restrict_base_for_decl, h, h->hash, INSERT);
+ *(struct tree_map **) loc = h;
+}
+
/* Print out the statistics for the DECL_DEBUG_EXPR hash table. */
static void
(long) htab_elements (value_expr_for_decl),
htab_collisions (value_expr_for_decl));
}
+
+/* Print out statistics for the RESTRICT_BASE_FOR_DECL hash table, but
+ don't print anything if the table is empty. */
+
+static void
+print_restrict_base_statistics (void)
+{
+ if (htab_elements (restrict_base_for_decl) != 0)
+ fprintf (stderr,
+ "RESTRICT_BASE hash: size %ld, %ld elements, %f collisions\n",
+ (long) htab_size (restrict_base_for_decl),
+ (long) htab_elements (restrict_base_for_decl),
+ htab_collisions (restrict_base_for_decl));
+}
+
/* Lookup a debug expression for FROM, and return it if we find one. */
tree
print_type_hash_statistics ();
print_debug_expr_statistics ();
print_value_expr_statistics ();
+ print_restrict_base_statistics ();
lang_hooks.print_statistics ();
}
\f