@@ -24,7 +24,9 @@ along with GCC; see the file COPYING3. If not see
#include "dmd/attrib.h"
#include "dmd/declaration.h"
+#include "dmd/module.h"
#include "dmd/mtype.h"
+#include "dmd/template.h"
#include "tree.h"
#include "diagnostic.h"
@@ -36,6 +38,8 @@ along with GCC; see the file COPYING3. If not see
#include "stringpool.h"
#include "attribs.h"
#include "varasm.h"
+#include "fold-const.h"
+#include "opts.h"
#include "d-tree.h"
@@ -53,17 +57,25 @@ static tree handle_type_generic_attribute (tree *, tree, tree, int, bool *);
static tree handle_transaction_pure_attribute (tree *, tree, tree, int, bool *);
static tree handle_returns_twice_attribute (tree *, tree, tree, int, bool *);
static tree handle_fnspec_attribute (tree *, tree, tree, int, bool *);
-static tree handle_always_inline_attribute (tree *, tree, tree, int, bool *);
/* D attribute handlers for user defined attributes. */
static tree d_handle_noinline_attribute (tree *, tree, tree, int, bool *);
-static tree d_handle_forceinline_attribute (tree *, tree, tree, int, bool *);
+static tree d_handle_always_inline_attribute (tree *, tree, tree, int, bool *);
static tree d_handle_flatten_attribute (tree *, tree, tree, int, bool *);
static tree d_handle_target_attribute (tree *, tree, tree, int, bool *);
+static tree d_handle_target_clones_attribute (tree *, tree, tree, int, bool *);
+static tree d_handle_optimize_attribute (tree *, tree, tree, int, bool *);
static tree d_handle_noclone_attribute (tree *, tree, tree, int, bool *);
+static tree d_handle_noicf_attribute (tree *, tree, tree, int, bool *);
+static tree d_handle_noipa_attribute (tree *, tree, tree, int, bool *);
static tree d_handle_section_attribute (tree *, tree, tree, int, bool *);
-static tree d_handle_alias_attribute (tree *, tree, tree, int, bool *);
+static tree d_handle_symver_attribute (tree *, tree, tree, int, bool *);
static tree d_handle_weak_attribute (tree *, tree, tree, int, bool *) ;
+static tree d_handle_noplt_attribute (tree *, tree, tree, int, bool *) ;
+static tree d_handle_alloc_size_attribute (tree *, tree, tree, int, bool *);
+static tree d_handle_cold_attribute (tree *, tree, tree, int, bool *);
+static tree d_handle_restrict_attribute (tree *, tree, tree, int, bool *);
+static tree d_handle_used_attribute (tree *, tree, tree, int, bool *);
/* Helper to define attribute exclusions. */
#define ATTR_EXCL(name, function, type, variable) \
@@ -72,6 +84,7 @@ static tree d_handle_weak_attribute (tree *, tree, tree, int, bool *) ;
/* Define attributes that are mutually exclusive with one another. */
static const struct attribute_spec::exclusions attr_noreturn_exclusions[] =
{
+ ATTR_EXCL ("alloc_size", true, true, true),
ATTR_EXCL ("const", true, true, true),
ATTR_EXCL ("malloc", true, true, true),
ATTR_EXCL ("pure", true, true, true),
@@ -87,6 +100,7 @@ static const struct attribute_spec::exclusions attr_returns_twice_exclusions[] =
static const struct attribute_spec::exclusions attr_const_pure_exclusions[] =
{
+ ATTR_EXCL ("alloc_size", true, true, true),
ATTR_EXCL ("const", true, true, true),
ATTR_EXCL ("noreturn", true, true, true),
ATTR_EXCL ("pure", true, true, true),
@@ -96,15 +110,44 @@ static const struct attribute_spec::exclusions attr_const_pure_exclusions[] =
static const struct attribute_spec::exclusions attr_inline_exclusions[] =
{
ATTR_EXCL ("noinline", true, true, true),
+ ATTR_EXCL ("target_clones", true, true, true),
ATTR_EXCL (NULL, false, false, false),
};
static const struct attribute_spec::exclusions attr_noinline_exclusions[] =
{
- ATTR_EXCL ("forceinline", true, true, true),
+ ATTR_EXCL ("always_inline", true, true, true),
ATTR_EXCL (NULL, false, false, false),
};
+static const struct attribute_spec::exclusions attr_target_exclusions[] =
+{
+ ATTR_EXCL ("target_clones", true, true, true),
+ ATTR_EXCL (NULL, false, false, false),
+};
+
+static const struct attribute_spec::exclusions attr_target_clones_exclusions[] =
+{
+ ATTR_EXCL ("always_inline", true, true, true),
+ ATTR_EXCL ("target", true, true, true),
+ ATTR_EXCL (NULL, false, false, false),
+};
+
+static const struct attribute_spec::exclusions attr_alloc_exclusions[] =
+{
+ ATTR_EXCL ("const", true, true, true),
+ ATTR_EXCL ("noreturn", true, true, true),
+ ATTR_EXCL ("pure", true, true, true),
+ ATTR_EXCL (NULL, false, false, false),
+};
+
+extern const struct attribute_spec::exclusions attr_cold_hot_exclusions[] =
+{
+ ATTR_EXCL ("cold", true, true, true),
+ ATTR_EXCL ("hot", true, true, true),
+ ATTR_EXCL (NULL, false, false, false)
+};
+
/* Helper to define an attribute. */
#define ATTR_SPEC(name, min_len, max_len, decl_req, type_req, fn_type_req, \
affects_type_identity, handler, exclude) \
@@ -139,8 +182,6 @@ const attribute_spec d_langhook_common_attribute_table[] =
handle_type_generic_attribute, NULL),
ATTR_SPEC ("fn spec", 1, 1, false, true, true, false,
handle_fnspec_attribute, NULL),
- ATTR_SPEC ("always_inline", 0, 0, true, false, false, false,
- handle_always_inline_attribute, NULL),
ATTR_SPEC (NULL, 0, 0, false, false, false, false, NULL, NULL),
};
@@ -149,20 +190,38 @@ const attribute_spec d_langhook_attribute_table[] =
{
ATTR_SPEC ("noinline", 0, 0, true, false, false, false,
d_handle_noinline_attribute, attr_noinline_exclusions),
- ATTR_SPEC ("forceinline", 0, 0, true, false, false, false,
- d_handle_forceinline_attribute, attr_inline_exclusions),
+ ATTR_SPEC ("always_inline", 0, 0, true, false, false, false,
+ d_handle_always_inline_attribute, attr_inline_exclusions),
ATTR_SPEC ("flatten", 0, 0, true, false, false, false,
d_handle_flatten_attribute, NULL),
ATTR_SPEC ("target", 1, -1, true, false, false, false,
- d_handle_target_attribute, NULL),
+ d_handle_target_attribute, attr_target_exclusions),
+ ATTR_SPEC ("target_clones", 1, -1, true, false, false, false,
+ d_handle_target_clones_attribute, attr_target_clones_exclusions),
+ ATTR_SPEC ("optimize", 1, -1, true, false, false, false,
+ d_handle_optimize_attribute, NULL),
ATTR_SPEC ("noclone", 0, 0, true, false, false, false,
d_handle_noclone_attribute, NULL),
+ ATTR_SPEC ("no_icf", 0, 0, true, false, false, false,
+ d_handle_noicf_attribute, NULL),
+ ATTR_SPEC ("noipa", 0, 0, true, false, false, false,
+ d_handle_noipa_attribute, NULL),
ATTR_SPEC ("section", 1, 1, true, false, false, false,
d_handle_section_attribute, NULL),
- ATTR_SPEC ("alias", 1, 1, true, false, false, false,
- d_handle_alias_attribute, NULL),
+ ATTR_SPEC ("symver", 1, -1, true, false, false, false,
+ d_handle_symver_attribute, NULL),
ATTR_SPEC ("weak", 0, 0, true, false, false, false,
d_handle_weak_attribute, NULL),
+ ATTR_SPEC ("noplt", 0, 0, true, false, false, false,
+ d_handle_noplt_attribute, NULL),
+ ATTR_SPEC ("alloc_size", 1, 3, false, true, true, false,
+ d_handle_alloc_size_attribute, attr_alloc_exclusions),
+ ATTR_SPEC ("cold", 0, 0, true, false, false, false,
+ d_handle_cold_attribute, attr_cold_hot_exclusions),
+ ATTR_SPEC ("restrict", 0, 0, true, false, false, false,
+ d_handle_restrict_attribute, NULL),
+ ATTR_SPEC ("used", 0, 0, true, false, false, false,
+ d_handle_used_attribute, NULL),
ATTR_SPEC (NULL, 0, 0, false, false, false, false, NULL, NULL),
};
@@ -254,11 +313,23 @@ build_attributes (Expressions *eattrs)
Dsymbol *sym = attr->type->toDsymbol (0);
if (!sym)
- continue;
+ {
+ /* If attribute is a template symbol, perhaps arguments were not
+ supplied, so warn about attribute having no effect. */
+ if (TemplateExp *te = attr->isTemplateExp ())
+ {
+ if (!te->td || !te->td->onemember)
+ continue;
+
+ sym = te->td->onemember;
+ }
+ else
+ continue;
+ }
/* Attribute symbol must come from the `gcc.attribute' module. */
- Dsymbol *mod = (Dsymbol *) sym->getModule ();
- if (!(strcmp (mod->toChars (), "attribute") == 0
+ Dsymbol *mod = sym->getModule ();
+ if (!(strcmp (mod->toChars (), "attributes") == 0
&& mod->parent != NULL
&& strcmp (mod->parent->toChars (), "gcc") == 0
&& !mod->parent->parent))
@@ -268,16 +339,24 @@ build_attributes (Expressions *eattrs)
if (attr->op == TOKcall)
attr = attr->ctfeInterpret ();
+ if (attr->op != TOKstructliteral)
+ {
+ warning_at (make_location_t (attr->loc), OPT_Wattributes,
+ "%qE attribute has no effect",
+ get_identifier (sym->toChars ()));
+ continue;
+ }
+
/* Should now have a struct `Attribute("attrib", "value", ...)'
initializer list. */
- gcc_assert (attr->op == TOKstructliteral);
Expressions *elems = attr->isStructLiteralExp ()->elements;
Expression *e0 = (*elems)[0];
if (e0->op != TOKstring)
{
- error ("expected string attribute, not %qs", e0->toChars ());
- return error_mark_node;
+ warning_at (make_location_t (attr->loc), OPT_Wattributes,
+ "unknown attribute %qs", e0->toChars());
+ continue;
}
StringExp *se = e0->toStringExp ();
@@ -292,9 +371,9 @@ build_attributes (Expressions *eattrs)
const char *name = (const char *)(se->len ? se->string : "");
if (!uda_attribute_p (name))
{
- warning_at (make_location_t (e0->loc), OPT_Wattributes,
+ warning_at (make_location_t (attr->loc), OPT_Wattributes,
"unknown attribute %qs", name);
- return error_mark_node;
+ continue;
}
/* Chain all attribute arguments together. */
@@ -303,6 +382,10 @@ build_attributes (Expressions *eattrs)
for (size_t j = 1; j < elems->length; j++)
{
Expression *e = (*elems)[j];
+ /* Stop after the first `void' argument. */
+ if (e == NULL)
+ break;
+
StringExp *s = e->isStringExp ();
tree t;
if (s != NULL && s->sz == 1)
@@ -523,7 +606,8 @@ handle_nothrow_attribute (tree *node, tree, tree, int, bool *)
return NULL_TREE;
}
-/* Handle a "type_generic" attribute. */
+/* Handle a "type generic" attribute; arguments as in
+ struct attribute_spec.handler. */
static tree
handle_type_generic_attribute (tree *node, tree, tree, int, bool *)
@@ -537,7 +621,8 @@ handle_type_generic_attribute (tree *node, tree, tree, int, bool *)
return NULL_TREE;
}
-/* Handle a "transaction_pure" attribute. */
+/* Handle a "transaction_pure" attribute; arguments as in
+ struct attribute_spec.handler. */
static tree
handle_transaction_pure_attribute (tree *node, tree, tree, int, bool *)
@@ -548,7 +633,8 @@ handle_transaction_pure_attribute (tree *node, tree, tree, int, bool *)
return NULL_TREE;
}
-/* Handle a "returns_twice" attribute. */
+/* Handle a "returns_twice" attribute; arguments as in
+ struct attribute_spec.handler. */
static tree
handle_returns_twice_attribute (tree *node, tree, tree, int, bool *)
@@ -572,30 +658,18 @@ handle_fnspec_attribute (tree *, tree, tree args, int, bool *)
return NULL_TREE;
}
-/* Handle a "always_inline" attribute; arguments as in
- struct attribute_spec.handler. */
-
-static tree
-handle_always_inline_attribute (tree *node, tree, tree, int, bool *)
-{
- gcc_assert (TREE_CODE (*node) == FUNCTION_DECL);
-
- return NULL_TREE;
-}
-
/* Language specific attribute handlers.
These functions take the arguments:
(tree *node, tree name, tree args, int flags, bool *no_add_attrs) */
-/* Handle a "noinline" attribute. */
+/* Handle a "noinline" attribute; arguments as in
+ struct attribute_spec.handler. */
static tree
d_handle_noinline_attribute (tree *node, tree name, tree, int,
bool *no_add_attrs)
{
- Type *t = TYPE_LANG_FRONTEND (TREE_TYPE (*node));
-
- if (t->ty == Tfunction)
+ if (TREE_CODE (*node) == FUNCTION_DECL)
DECL_UNINLINABLE (*node) = 1;
else
{
@@ -606,25 +680,16 @@ d_handle_noinline_attribute (tree *node, tree name, tree, int,
return NULL_TREE;
}
-/* Handle a "forceinline" attribute. */
+/* Handle a "always_inline" attribute; arguments as in
+ struct attribute_spec.handler. */
static tree
-d_handle_forceinline_attribute (tree *node, tree name, tree, int,
- bool *no_add_attrs)
+d_handle_always_inline_attribute (tree *node, tree name, tree, int,
+ bool *no_add_attrs)
{
- Type *t = TYPE_LANG_FRONTEND (TREE_TYPE (*node));
-
- if (t->ty == Tfunction)
+ if (TREE_CODE (*node) == FUNCTION_DECL)
{
- tree attributes = DECL_ATTRIBUTES (*node);
-
- /* Push attribute always_inline. */
- if (!lookup_attribute ("always_inline", attributes))
- DECL_ATTRIBUTES (*node) = tree_cons (get_identifier ("always_inline"),
- NULL_TREE, attributes);
-
DECL_DECLARED_INLINE_P (*node) = 1;
- DECL_NO_INLINE_WARNING_P (*node) = 1;
DECL_DISREGARD_INLINE_LIMITS (*node) = 1;
}
else
@@ -636,15 +701,14 @@ d_handle_forceinline_attribute (tree *node, tree name, tree, int,
return NULL_TREE;
}
-/* Handle a "flatten" attribute. */
+/* Handle a "flatten" attribute; arguments as in
+ struct attribute_spec.handler. */
static tree
d_handle_flatten_attribute (tree *node, tree name, tree, int,
bool *no_add_attrs)
{
- Type *t = TYPE_LANG_FRONTEND (TREE_TYPE (*node));
-
- if (t->ty != Tfunction)
+ if (TREE_CODE (*node) != FUNCTION_DECL)
{
warning (OPT_Wattributes, "%qE attribute ignored", name);
*no_add_attrs = true;
@@ -653,16 +717,15 @@ d_handle_flatten_attribute (tree *node, tree name, tree, int,
return NULL_TREE;
}
-/* Handle a "target" attribute. */
+/* Handle a "target" attribute; arguments as in
+ struct attribute_spec.handler. */
static tree
d_handle_target_attribute (tree *node, tree name, tree args, int flags,
bool *no_add_attrs)
{
- Type *t = TYPE_LANG_FRONTEND (TREE_TYPE (*node));
-
/* Ensure we have a function type. */
- if (t->ty != Tfunction)
+ if (TREE_CODE (*node) != FUNCTION_DECL)
{
warning (OPT_Wattributes, "%qE attribute ignored", name);
*no_add_attrs = true;
@@ -670,152 +733,368 @@ d_handle_target_attribute (tree *node, tree name, tree args, int flags,
else if (!targetm.target_option.valid_attribute_p (*node, name, args, flags))
*no_add_attrs = true;
+ /* Check that there's no empty string in values of the attribute. */
+ for (tree t = args; t != NULL_TREE; t = TREE_CHAIN (t))
+ {
+ tree value = TREE_VALUE (t);
+ if (TREE_CODE (value) != STRING_CST
+ || (TREE_STRING_LENGTH (value) != 0
+ && TREE_STRING_POINTER (value)[0] != '\0'))
+ continue;
+
+ warning (OPT_Wattributes, "empty string in attribute %<target%>");
+ *no_add_attrs = true;
+ }
+
return NULL_TREE;
}
-/* Handle a "noclone" attribute. */
+/* Handle a "target_clones" attribute; arguments as in
+ struct attribute_spec.handler. */
static tree
-d_handle_noclone_attribute (tree *node, tree name, tree, int,
- bool *no_add_attrs)
+d_handle_target_clones_attribute (tree *node, tree name, tree, int,
+ bool *no_add_attrs)
{
- Type *t = TYPE_LANG_FRONTEND (TREE_TYPE (*node));
-
- if (t->ty == Tfunction)
+ /* Ensure we have a function type. */
+ if (TREE_CODE (*node) != FUNCTION_DECL)
{
- tree attributes = DECL_ATTRIBUTES (*node);
-
- /* Push attribute noclone. */
- if (!lookup_attribute ("noclone", attributes))
- DECL_ATTRIBUTES (*node) = tree_cons (get_identifier ("noclone"),
- NULL_TREE, attributes);
+ warning (OPT_Wattributes, "%qE attribute ignored", name);
+ *no_add_attrs = true;
}
else
{
- warning (OPT_Wattributes, "%qE attribute ignored", name);
- *no_add_attrs = true;
+ /* Do not inline functions with multiple clone targets. */
+ DECL_UNINLINABLE (*node) = 1;
}
return NULL_TREE;
}
-/* Handle a "section" attribute; arguments as in
- struct attribute_spec.handler. */
+/* Arguments being collected for optimization. */
+static GTY(()) vec <const char *, va_gc> *optimize_args;
-static tree
-d_handle_section_attribute (tree *node, tree, tree args, int,
- bool *no_add_attrs)
+/* Inner function to convert a TREE_LIST to argv string to parse the optimize
+ options in ARGS. */
+
+static bool
+parse_optimize_options (tree args)
{
- tree decl = *node;
+ bool ret = true;
+
+ /* Build up argv vector. Just in case the string is stored away, use garbage
+ collected strings. */
+ vec_safe_truncate (optimize_args, 0);
+ vec_safe_push (optimize_args, (const char *) NULL);
- if (targetm_common.have_named_sections)
+ for (tree ap = args; ap != NULL_TREE; ap = TREE_CHAIN (ap))
{
- if (VAR_OR_FUNCTION_DECL_P (decl)
- && TREE_CODE (TREE_VALUE (args)) == STRING_CST)
+ tree value = TREE_VALUE (ap);
+
+ if (TREE_CODE (value) == INTEGER_CST)
{
- if (VAR_P (decl)
- && current_function_decl != NULL_TREE
- && !TREE_STATIC (decl))
- {
- error_at (DECL_SOURCE_LOCATION (decl),
- "section attribute cannot be specified for "
- "local variables");
- *no_add_attrs = true;
- }
+ char buffer[20];
+ sprintf (buffer, "-O%ld", (long) TREE_INT_CST_LOW (value));
+ vec_safe_push (optimize_args, ggc_strdup (buffer));
+ }
+ else if (TREE_CODE (value) == STRING_CST)
+ {
+ size_t len = TREE_STRING_LENGTH (value);
+ const char *p = TREE_STRING_POINTER (value);
- /* The decl may have already been given a section attribute
- from a previous declaration. Ensure they match. */
- else if (DECL_SECTION_NAME (decl) != NULL
- && strcmp (DECL_SECTION_NAME (decl),
- TREE_STRING_POINTER (TREE_VALUE (args))) != 0)
+ /* If the user supplied -Oxxx or -fxxx, only allow -Oxxx or -fxxx
+ options. */
+ if (*p == '-' && p[1] != 'O' && p[1] != 'f')
{
- error ("section of %q+D conflicts with previous declaration",
- *node);
- *no_add_attrs = true;
+ ret = false;
+ warning (OPT_Wattributes,
+ "bad option %qs to attribute %<optimize%>", p);
+ continue;
}
- else if (VAR_P (decl)
- && !targetm.have_tls && targetm.emutls.tmpl_section
- && DECL_THREAD_LOCAL_P (decl))
+
+ /* Can't use GC memory here. */
+ char *q = XOBNEWVEC (&opts_obstack, char, len + 3);
+ char *r = q;
+
+ if (*p != '-')
{
- error ("section of %q+D cannot be overridden", *node);
- *no_add_attrs = true;
+ *r++ = '-';
+
+ /* Assume that Ox is -Ox, a numeric value is -Ox, a s by
+ itself is -Os, and any other switch begins with a -f. */
+ if ((*p >= '0' && *p <= '9') || (p[0] == 's' && p[1] == '\0'))
+ *r++ = 'O';
+ else if (*p != 'O')
+ *r++ = 'f';
}
- else
- set_decl_section_name (decl,
- TREE_STRING_POINTER (TREE_VALUE (args)));
+
+ memcpy (r, p, len);
+ r[len] = '\0';
+ vec_safe_push (optimize_args, (const char *) q);
}
- else
+ }
+
+ unsigned opt_argc = optimize_args->length ();
+ const char **opt_argv
+ = (const char **) alloca (sizeof (char *) * (opt_argc + 1));
+
+ for (unsigned i = 1; i < opt_argc; i++)
+ opt_argv[i] = (*optimize_args)[i];
+
+ /* Now parse the options. */
+ struct cl_decoded_option *decoded_options;
+ unsigned int decoded_options_count;
+
+ decode_cmdline_options_to_array_default_mask (opt_argc, opt_argv,
+ &decoded_options,
+ &decoded_options_count);
+ /* Drop non-Optimization options. */
+ unsigned j = 1;
+ for (unsigned i = 1; i < decoded_options_count; ++i)
+ {
+ if (! (cl_options[decoded_options[i].opt_index].flags & CL_OPTIMIZATION))
{
- error ("section attribute not allowed for %q+D", *node);
- *no_add_attrs = true;
+ ret = false;
+ warning (OPT_Wattributes,
+ "bad option %qs to attribute %<optimize%>",
+ decoded_options[i].orig_option_with_args_text);
+ continue;
}
+ if (i != j)
+ decoded_options[j] = decoded_options[i];
+ j++;
+ }
+ decoded_options_count = j;
+ /* And apply them. */
+ decode_options (&global_options, &global_options_set,
+ decoded_options, decoded_options_count,
+ input_location, global_dc, NULL);
+
+ targetm.override_options_after_change();
+
+ optimize_args->truncate (0);
+ return ret;
+}
+
+/* Handle a "optimize" attribute; arguments as in
+ struct attribute_spec.handler. */
+
+static tree
+d_handle_optimize_attribute (tree *node, tree name, tree args, int,
+ bool *no_add_attrs)
+{
+ /* Ensure we have a function type. */
+ if (TREE_CODE (*node) != FUNCTION_DECL)
+ {
+ warning (OPT_Wattributes, "%qE attribute ignored", name);
+ *no_add_attrs = true;
}
else
{
- error_at (DECL_SOURCE_LOCATION (*node),
- "section attributes are not supported for this target");
+ struct cl_optimization cur_opts;
+ tree old_opts = DECL_FUNCTION_SPECIFIC_OPTIMIZATION (*node);
+
+ /* Save current options. */
+ cl_optimization_save (&cur_opts, &global_options, &global_options_set);
+
+ /* If we previously had some optimization options, use them as the
+ default. */
+ gcc_options *saved_global_options = NULL;
+ if (flag_checking)
+ {
+ saved_global_options = XNEW (gcc_options);
+ *saved_global_options = global_options;
+ }
+
+ if (old_opts)
+ cl_optimization_restore (&global_options, &global_options_set,
+ TREE_OPTIMIZATION (old_opts));
+
+ /* Parse options, and update the vector. */
+ parse_optimize_options (args);
+ DECL_FUNCTION_SPECIFIC_OPTIMIZATION (*node)
+ = build_optimization_node (&global_options, &global_options_set);
+
+ /* Restore current options. */
+ cl_optimization_restore (&global_options, &global_options_set,
+ &cur_opts);
+ if (saved_global_options != NULL)
+ {
+ cl_optimization_compare (saved_global_options, &global_options);
+ free (saved_global_options);
+ }
+ }
+
+ return NULL_TREE;
+}
+
+/* Handle a "noclone" attribute; arguments as in
+ struct attribute_spec.handler. */
+
+static tree
+d_handle_noclone_attribute (tree *node, tree name, tree, int,
+ bool *no_add_attrs)
+{
+ if (TREE_CODE (*node) != FUNCTION_DECL)
+ {
+ warning (OPT_Wattributes, "%qE attribute ignored", name);
*no_add_attrs = true;
}
return NULL_TREE;
}
-/* Handle an "alias" attribute; arguments as in
+/* Handle a "no_icf" attribute; arguments as in
struct attribute_spec.handler. */
static tree
-d_handle_alias_attribute (tree *node, tree name, tree args, int,
+d_handle_noicf_attribute (tree *node, tree name, tree, int,
bool *no_add_attrs)
{
- tree decl = *node;
+ if (TREE_CODE (*node) != FUNCTION_DECL)
+ {
+ warning (OPT_Wattributes, "%qE attribute ignored", name);
+ *no_add_attrs = true;
+ }
+
+ return NULL_TREE;
+}
- if (TREE_CODE (decl) != FUNCTION_DECL
- && TREE_CODE (decl) != VAR_DECL)
+/* Handle a "noipa" attribute; arguments as in
+ struct attribute_spec.handler. */
+
+static tree
+d_handle_noipa_attribute (tree *node, tree name, tree, int,
+ bool *no_add_attrs)
+{
+ if (TREE_CODE (*node) != FUNCTION_DECL)
{
warning (OPT_Wattributes, "%qE attribute ignored", name);
*no_add_attrs = true;
+ }
+
+ return NULL_TREE;
+}
+
+/* Handle a "section" attribute; arguments as in
+ struct attribute_spec.handler. */
+
+static tree
+d_handle_section_attribute (tree *node, tree name, tree args, int flags,
+ bool *no_add_attrs)
+{
+ if (!targetm_common.have_named_sections)
+ {
+ error ("section attributes are not supported for this target");
+ *no_add_attrs = true;
return NULL_TREE;
}
- else if ((TREE_CODE (decl) == FUNCTION_DECL && DECL_INITIAL (decl))
- || (TREE_CODE (decl) != FUNCTION_DECL
- && TREE_PUBLIC (decl) && !DECL_EXTERNAL (decl))
- /* A static variable declaration is always a tentative definition,
- but the alias is a non-tentative definition which overrides. */
- || (TREE_CODE (decl) != FUNCTION_DECL
- && !TREE_PUBLIC (decl) && DECL_INITIAL (decl)))
+
+ if (!VAR_OR_FUNCTION_DECL_P (*node))
{
- error ("%q+D defined both normally and as %qE attribute", decl, name);
+ error ("section attribute not allowed for %q+D", *node);
*no_add_attrs = true;
return NULL_TREE;
}
- else if (decl_function_context (decl))
+
+ if (TREE_CODE (TREE_VALUE (args)) != STRING_CST)
{
- error ("%q+D alias functions must be global", name);
+ error ("section attribute argument not a string constant");
*no_add_attrs = true;
return NULL_TREE;
}
- else
+
+ if (VAR_P (*node)
+ && current_function_decl != NULL_TREE
+ && !TREE_STATIC (*node))
{
- tree id;
+ error ("section attribute cannot be specified for local variables");
+ *no_add_attrs = true;
+ return NULL_TREE;
+ }
- id = TREE_VALUE (args);
- if (TREE_CODE (id) != STRING_CST)
+ /* The decl may have already been given a section attribute
+ from a previous declaration. Ensure they match. */
+ if (DECL_SECTION_NAME (*node) != NULL
+ && strcmp (DECL_SECTION_NAME (*node),
+ TREE_STRING_POINTER (TREE_VALUE (args))) != 0)
+ {
+ error ("section of %q+D conflicts with previous declaration", *node);
+ *no_add_attrs = true;
+ return NULL_TREE;
+ }
+
+ if (VAR_P (*node)
+ && !targetm.have_tls && targetm.emutls.tmpl_section
+ && DECL_THREAD_LOCAL_P (*node))
+ {
+ error ("section of %q+D cannot be overridden", *node);
+ *no_add_attrs = true;
+ return NULL_TREE;
+ }
+
+ tree res = targetm.handle_generic_attribute (node, name, args, flags,
+ no_add_attrs);
+
+ /* If the back end confirms the attribute can be added then continue onto
+ final processing. */
+ if (*no_add_attrs)
+ return NULL_TREE;
+
+ set_decl_section_name (*node, TREE_STRING_POINTER (TREE_VALUE (args)));
+ return res;
+}
+
+/* Handle a "symver" and attribute; arguments as in
+ struct attribute_spec.handler. */
+
+static tree
+d_handle_symver_attribute (tree *node, tree, tree args, int, bool *no_add_attrs)
+{
+ if (TREE_CODE (*node) != FUNCTION_DECL && TREE_CODE (*node) != VAR_DECL)
+ {
+ warning (OPT_Wattributes,
+ "%<symver%> attribute only applies to functions and variables");
+ *no_add_attrs = true;
+ return NULL_TREE;
+ }
+
+ if (!decl_in_symtab_p (*node))
+ {
+ warning (OPT_Wattributes,
+ "%<symver%> attribute is only applicable to symbols");
+ *no_add_attrs = true;
+ return NULL_TREE;
+ }
+
+ for (; args; args = TREE_CHAIN (args))
+ {
+ tree symver = TREE_VALUE (args);
+ if (TREE_CODE (symver) != STRING_CST)
{
- error ("attribute %qE argument not a string", name);
+ error ("%<symver%> attribute argument not a string constant");
*no_add_attrs = true;
return NULL_TREE;
}
- id = get_identifier (TREE_STRING_POINTER (id));
- /* This counts as a use of the object pointed to. */
- TREE_USED (id) = 1;
- if (TREE_CODE (decl) == FUNCTION_DECL)
- DECL_INITIAL (decl) = error_mark_node;
- else
- TREE_STATIC (decl) = 1;
+ const char *symver_str = TREE_STRING_POINTER (symver);
- return NULL_TREE;
+ int ats = 0;
+ for (int n = 0; (int)n < TREE_STRING_LENGTH (symver); n++)
+ if (symver_str[n] == '@')
+ ats++;
+
+ if (ats != 1 && ats != 2)
+ {
+ error ("symver attribute argument must have format %<name@nodename%>");
+ error ("%<symver%> attribute argument %qs must contain one or two "
+ "%<@%>", symver_str);
+ *no_add_attrs = true;
+ return NULL_TREE;
+ }
}
+
+ return NULL_TREE;
}
/* Handle a "weak" attribute; arguments as in
@@ -843,3 +1122,279 @@ d_handle_weak_attribute (tree *node, tree name, tree, int, bool *no_add_attrs)
return NULL_TREE;
}
+/* Handle a "noplt" attribute; arguments as in
+ struct attribute_spec.handler. */
+
+static tree
+d_handle_noplt_attribute (tree *node, tree name, tree, int, bool *no_add_attrs)
+{
+ if (TREE_CODE (*node) != FUNCTION_DECL)
+ {
+ warning (OPT_Wattributes, "%qE attribute ignored", name);
+ *no_add_attrs = true;
+ }
+
+ return NULL_TREE;
+}
+
+/* Verify that argument value POS at position ARGNO to attribute ATNAME applied
+ to function FNTYPE refers to a function parameter at position POS and is a
+ valid integer type. When ZERO_BASED is true, POS is adjusted to be 1-based.
+ If successful, POS is returned. Otherwise, issue appropriate warnings and
+ return null. A non-zero 1-based ARGNO should be passed in by callers only
+ for attributes with more than one argument. */
+
+static tree
+positional_argument (const_tree fntype, const_tree atname, tree pos,
+ int argno, bool zero_based)
+{
+ tree postype = TREE_TYPE (pos);
+
+ if (pos == error_mark_node || !postype)
+ {
+ /* Only mention the positional argument number when it's non-zero. */
+ if (argno < 1)
+ warning (OPT_Wattributes,
+ "%qE attribute argument is invalid", atname);
+ else
+ warning (OPT_Wattributes,
+ "%qE attribute argument %i is invalid", atname, argno);
+
+ return NULL_TREE;
+ }
+
+ if (!INTEGRAL_TYPE_P (postype))
+ {
+ /* Handle this case specially to avoid mentioning the value
+ of pointer constants in diagnostics. Only mention
+ the positional argument number when it's non-zero. */
+ if (argno < 1)
+ warning (OPT_Wattributes,
+ "%qE attribute argument has type %qT",
+ atname, postype);
+ else
+ warning (OPT_Wattributes,
+ "%qE attribute argument %i has type %qT",
+ atname, argno, postype);
+
+ return NULL_TREE;
+ }
+
+ if (TREE_CODE (pos) != INTEGER_CST)
+ {
+ /* Only mention the argument number when it's non-zero. */
+ if (argno < 1)
+ warning (OPT_Wattributes,
+ "%qE attribute argument value %qE is not an integer "
+ "constant",
+ atname, pos);
+ else
+ warning (OPT_Wattributes,
+ "%qE attribute argument %i value %qE is not an integer "
+ "constant",
+ atname, argno, pos);
+
+ return NULL_TREE;
+ }
+
+ /* Validate the value of the position argument. If 0-based, then it should
+ not be negative. If 1-based, it should be greater than zero. */
+ if ((zero_based && tree_int_cst_sgn (pos) < 0)
+ || (!zero_based && tree_int_cst_sgn (pos) < 1))
+ {
+ if (argno < 1)
+ warning (OPT_Wattributes,
+ "%qE attribute argument value %qE does not refer to "
+ "a function parameter",
+ atname, pos);
+ else
+ warning (OPT_Wattributes,
+ "%qE attribute argument %i value %qE does not refer to "
+ "a function parameter",
+ atname, argno, pos);
+
+ return NULL_TREE;
+ }
+
+ /* Adjust the value of pos to be 1-based. */
+ tree adjusted_pos = (zero_based)
+ ? int_const_binop (PLUS_EXPR, pos, integer_one_node) : pos;
+
+ if (!prototype_p (fntype))
+ return adjusted_pos;
+
+ /* Verify that the argument position does not exceed the number
+ of formal arguments to the function. */
+ unsigned nargs = type_num_arguments (fntype);
+ if (!nargs
+ || !tree_fits_uhwi_p (adjusted_pos)
+ || !IN_RANGE (tree_to_uhwi (adjusted_pos), 1, nargs))
+ {
+ if (argno < 1)
+ warning (OPT_Wattributes,
+ "%qE attribute argument value %qE exceeds the number "
+ "of function parameters %u",
+ atname, pos, nargs);
+ else
+ warning (OPT_Wattributes,
+ "%qE attribute argument %i value %qE exceeds the number "
+ "of function parameters %u",
+ atname, argno, pos, nargs);
+
+ return NULL_TREE;
+ }
+
+ /* Verify that the type of the referenced formal argument matches
+ the expected type. */
+ unsigned HOST_WIDE_INT ipos = tree_to_uhwi (adjusted_pos);
+
+ /* Zero was handled above. */
+ gcc_assert (ipos != 0);
+
+ if (tree argtype = type_argument_type (fntype, ipos))
+ {
+ /* Accept types that match INTEGRAL_TYPE_P except for bool. */
+ if (!INTEGRAL_TYPE_P (argtype) || TREE_CODE (argtype) == BOOLEAN_TYPE)
+ {
+ if (argno < 1)
+ warning (OPT_Wattributes,
+ "%qE attribute argument value %qE refers to "
+ "parameter type %qT",
+ atname, pos, argtype);
+ else
+ warning (OPT_Wattributes,
+ "%qE attribute argument %i value %qE refers to "
+ "parameter type %qT",
+ atname, argno, pos, argtype);
+
+ return NULL_TREE;
+ }
+
+ return adjusted_pos;
+ }
+
+ /* Argument position exceeding number of parameters was handled above. */
+ gcc_unreachable ();
+}
+
+/* Handle a "alloc_size" attribute; arguments as in
+ struct attribute_spec.handler. */
+
+static tree
+d_handle_alloc_size_attribute (tree *node, tree name, tree args, int,
+ bool *no_add_attrs)
+{
+ tree fntype = *node;
+ tree rettype = TREE_TYPE (fntype);
+ if (!POINTER_TYPE_P (rettype))
+ {
+ warning (OPT_Wattributes,
+ "%qE attribute ignored on a function returning %qT",
+ name, rettype);
+ *no_add_attrs = true;
+ return NULL_TREE;
+ }
+
+ /* The first argument SIZE_ARG is never null. */
+ tree size_arg = TREE_VALUE (args);
+ tree next = TREE_CHAIN (args);
+
+ /* NUM_ARG is null when the attribute includes just one argument, or is
+ explictly set to null if it has been left uninitialized by the caller. */
+ tree num_arg = NULL_TREE;
+ if (next != NULL_TREE)
+ {
+ if (TREE_VALUE (next) != TYPE_MIN_VALUE (d_int_type))
+ num_arg = TREE_VALUE (next);
+
+ next = TREE_CHAIN (next);
+ }
+
+ /* If ZERO_ARG is set and true, arguments positions are treated as 0-based.
+ Otherwise the default is 1-based. */
+ bool zero_based = false;
+ if (next != NULL_TREE)
+ zero_based = integer_truep (TREE_VALUE (next));
+
+ /* Update the argument values with the real argument position. */
+ if (tree val = positional_argument (fntype, name, size_arg, num_arg ? 1 : 0,
+ zero_based))
+ TREE_VALUE (args) = val;
+ else
+ *no_add_attrs = true;
+
+ if (num_arg != NULL_TREE)
+ {
+ args = TREE_CHAIN (args);
+ if (tree val = positional_argument (fntype, name, num_arg, 2, zero_based))
+ TREE_VALUE (args) = val;
+ else
+ *no_add_attrs = true;
+ }
+
+ /* Terminate the original TREE_CHAIN in `args' to remove any remaining
+ D-specific `alloc_size` arguments. */
+ TREE_CHAIN (args) = NULL_TREE;
+
+ return NULL_TREE;
+}
+
+/* Handle a "cold" and attribute; arguments as in
+ struct attribute_spec.handler. */
+
+static tree
+d_handle_cold_attribute (tree *node, tree name, tree, int, bool *no_add_attrs)
+{
+ if (TREE_CODE (*node) != FUNCTION_DECL)
+ {
+ warning (OPT_Wattributes, "%qE attribute ignored", name);
+ *no_add_attrs = true;
+ }
+
+ return NULL_TREE;
+}
+
+/* Handle a "restrict" attribute; arguments as in
+ struct attribute_spec.handler. */
+
+static tree
+d_handle_restrict_attribute (tree *node, tree name, tree, int,
+ bool *no_add_attrs)
+{
+ if (TREE_CODE (*node) == PARM_DECL && POINTER_TYPE_P (TREE_TYPE (*node)))
+ {
+ TREE_TYPE (*node) = build_qualified_type (TREE_TYPE (*node),
+ TYPE_QUAL_RESTRICT);
+ }
+ else
+ {
+ warning (OPT_Wattributes, "%qE attribute ignored", name);
+ *no_add_attrs = true;
+ }
+
+ return NULL_TREE;
+}
+
+/* Handle a "used" attribute; arguments as in
+ struct attribute_spec.handler. */
+
+static tree
+d_handle_used_attribute (tree *node, tree name, tree, int, bool *no_add_attrs)
+{
+ if (TREE_CODE (*node) == FUNCTION_DECL
+ || (VAR_P (*node) && TREE_STATIC (*node))
+ || (TREE_CODE (*node) == TYPE_DECL))
+ {
+ TREE_USED (*node) = 1;
+ DECL_PRESERVE_P (*node) = 1;
+ if (VAR_P (*node))
+ DECL_READ_P (*node) = 1;
+ }
+ else
+ {
+ warning (OPT_Wattributes, "%qE attribute ignored", name);
+ *no_add_attrs = true;
+ }
+
+ return NULL_TREE;
+}
@@ -108,7 +108,7 @@ gcc_attribute_p (Dsymbol *decl)
if (md && md->packages && md->packages->length == 1)
{
if (!strcmp ((*md->packages)[0]->toChars (), "gcc")
- && !strcmp (md->id->toChars (), "attribute"))
+ && !strcmp (md->id->toChars (), "attributes"))
return true;
}
@@ -1124,6 +1124,10 @@ get_symbol_decl (Declaration *decl)
tree olddecl = decl->csym;
decl->csym = get_symbol_decl (other);
+ /* Update the symbol location to the current definition. */
+ if (DECL_EXTERNAL (decl->csym) && !DECL_INITIAL (decl->csym))
+ DECL_SOURCE_LOCATION (decl->csym) = DECL_SOURCE_LOCATION (olddecl);
+
/* The current declaration is a prototype or marked extern, merge
applied user attributes and return. */
if (DECL_EXTERNAL (olddecl) && !DECL_INITIAL (olddecl))
@@ -354,6 +354,7 @@ layout_aggregate_members (Dsymbols *members, tree context, bool inherited_p)
const char *ident = var->ident ? var->ident->toChars () : NULL;
tree field = create_field_decl (declaration_type (var), ident,
inherited_p, inherited_p);
+ apply_user_attributes (var, field);
insert_aggregate_field (context, field, var->offset);
/* Because the front-end shares field decls across classes, don't
@@ -403,6 +404,7 @@ layout_aggregate_members (Dsymbols *members, tree context, bool inherited_p)
/* And make the corresponding data member. */
tree field = create_field_decl (type, NULL, 0, 0);
+ apply_user_attributes (ad, field);
insert_aggregate_field (context, field, ad->anonoffset);
continue;
}
new file mode 100644
@@ -0,0 +1,44 @@
+// { dg-do compile }
+
+import gcc.attributes;
+
+@alloc_size(1)
+int ignoredfunc(int size); // { dg-warning ".alloc_size. attribute ignored on a function returning .int." }
+
+@alloc_size(0) int var; // { dg-warning ".alloc_size. attribute only applies to function types" }
+
+@attribute("alloc_size", "1")
+void* invalid1(int size); // { dg-warning ".alloc_size. attribute argument is invalid" }
+
+@attribute("alloc_size", 1, "2")
+void* invalid2(int count, int size); // { dg-warning ".alloc_size. attribute argument 2 is invalid" }
+
+@attribute("alloc_size", 0.1)
+void* wrongtype1(int size); // { dg-warning ".alloc_size. attribute argument has type .double." }
+
+@attribute("alloc_size", 1, 0.2)
+void* wrongtype2(int count, int size); // { dg-warning ".alloc_size. attribute argument 2 has type .double." }
+
+@alloc_size(0)
+void* malloc0(int size); // { dg-warning ".alloc_size. attribute argument value .0. does not refer to a function parameter" }
+
+@alloc_size(1, 0)
+void* malloc0(int count, int size); // { dg-warning ".alloc_size. attribute argument 2 value .0. does not refer to a function parameter" }
+
+@alloc_size(1, 0, true)
+void* malloc0pos(int count, int size);
+
+@alloc_size(1, -1, true)
+void* mallocminus1(int count, int size); // { dg-warning ".alloc_size. attribute argument 2 value .-1. does not refer to a function parameter" }
+
+@alloc_size(99)
+void* malloc99(int size); // { dg-warning ".alloc_size. attribute argument value .99. exceeds the number of function parameters 1" }
+
+@alloc_size(1, 99)
+void* malloc99(int count, int size); // { dg-warning ".alloc_size. attribute argument 2 value .99. exceeds the number of function parameters 2" }
+
+@alloc_size(1)
+void* mallocdouble(double size); // { dg-warning ".alloc_size. attribute argument value .1. refers to parameter type .double." }
+
+@alloc_size(2, 1)
+void* mallocdouble(int count, double size); // { dg-warning ".alloc_size. attribute argument 1 value .2. refers to parameter type .double." }
new file mode 100644
@@ -0,0 +1,13 @@
+// { dg-do compile }
+
+import gcc.attributes;
+
+void* my_calloc(size_t num, size_t size) @allocSize(1, 0)
+{
+ return null;
+}
+
+void* my_malloc(int a, int b, size_t size, int c) @allocSize(2)
+{
+ return null;
+}
new file mode 100644
@@ -0,0 +1,17 @@
+// { dg-do compile }
+// { dg-options "-O0" }
+
+import gcc.attributes;
+
+int func()
+{
+ int nested_function() @always_inline
+ {
+ return 13;
+ }
+ return nested_function();
+}
+
+@always_inline int var = 0; // { dg-warning ".always_inline. attribute ignored" }
+
+// { dg-final { scan-assembler-not "nested_function" } }
new file mode 100644
@@ -0,0 +1,13 @@
+// { dg-do compile }
+// { dg-options "-O2 -fdump-tree-optimized" }
+
+import gcc.attributes;
+
+int func() @cold
+{
+ return 0;
+}
+
+@cold int var = 0; // { dg-warning ".cold. attribute ignored" }
+
+// { dg-final { scan-tree-dump "func\[^\r\n\]*(unlikely executed)" "optimized" } }
new file mode 100644
@@ -0,0 +1,19 @@
+// { dg-do compile }
+
+import gcc.attributes;
+
+// always_inline
+
+@noinline
+@always_inline
+void i0(); // { dg-warning "ignoring attribute .always_inline. because it conflicts with attribute .noinline." }
+
+@target_clones("")
+@always_inline
+void i1(); // { dg-warning "ignoring attribute .always_inline. because it conflicts with attribute .target_clones." }
+
+// noinline
+
+@always_inline
+@noinline
+void n0(); // { dg-warning "ignoring attribute .noinline. because it conflicts with attribute .always_inline." }
new file mode 100644
@@ -0,0 +1,19 @@
+// { dg-do compile { target x86_64-*-* } }
+
+import gcc.attributes;
+
+// target
+
+@target_clones("default")
+@target("default")
+void tc0(); // { dg-warning "ignoring attribute .target. because it conflicts with attribute .target_clones." }
+
+// target_clones
+
+@target("default")
+@target_clones("default")
+void t0(); // { dg-warning "ignoring attribute .target_clones. because it conflicts with attribute .target." }
+
+@always_inline
+@target_clones("default")
+void tc1(); // { dg-warning "ignoring attribute .target_clones. because it conflicts with attribute .always_inline." }
new file mode 100644
@@ -0,0 +1,21 @@
+// { dg-do compile }
+// { dg-options "-O1" }
+
+import gcc.attributes;
+
+int func() @flatten
+{
+ __gshared int count = 0;
+ int nested_function()
+ {
+ return count++;
+ }
+ static foreach (_; 0 .. 1000)
+ nested_function();
+
+ return nested_function();
+}
+
+@flatten int var = 0; // { dg-warning ".flatten. attribute ignored" }
+
+// { dg-final { scan-assembler-not "nested_function" } }
new file mode 100644
@@ -0,0 +1,40 @@
+// { dg-do compile }
+// { dg-additional-sources "imports/attributes.d" }
+
+import gcc.attributes;
+
+@value_ignored
+int f0()
+{
+ return 0;
+}
+
+@type_symbol // { dg-warning ".type_symbol. attribute has no effect" }
+int f1()
+{
+ return 1;
+}
+
+@template_symbol // { dg-warning ".template_symbol. attribute has no effect" }
+int f2()
+{
+ return 2;
+}
+
+@struct_wrong_field(123) // { dg-warning "unknown attribute .123." }
+int f3()
+{
+ return 3;
+}
+
+@struct_void_init()
+int f4()
+{
+ return 4;
+}
+
+@unknown_attribute() // { dg-warning "unknown attribute .made up name." }
+int f5()
+{
+ return 5;
+}
new file mode 100644
@@ -0,0 +1,12 @@
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+
+import gcc.attributes;
+
+@target_clones("avx", "default")
+@noclone
+void func() // { dg-error "clones for .target_clones. attribute cannot be created" }
+{ // { dg-message "function .func. can never be copied because it has .noclone. attribute" "" { target *-*-* } .-1 }
+}
+
+@noclone int var = 0; // { dg-warning ".noclone. attribute ignored" }
new file mode 100644
@@ -0,0 +1,30 @@
+// { dg-do compile }
+// { dg-options "-O2 -fno-inline" }
+
+import gcc.attributes;
+
+extern int t();
+
+int func()
+{
+ __gshared int var = 42;
+ int nested_1() @no_icf
+ {
+ return var++;
+ }
+ int nested_2()
+ {
+ return var++;
+ }
+ int nested_3()
+ {
+ return var++;
+ }
+ return nested_1() + nested_2() + nested_3();
+}
+
+@no_icf int var = 0; // { dg-warning ".no_icf. attribute ignored" }
+
+// { dg-final { scan-assembler "nested_1" } }
+// { dg-final { scan-assembler "nested_2" } }
+// { dg-final { scan-assembler-not "nested_3" } }
new file mode 100644
@@ -0,0 +1,19 @@
+// { dg-do compile }
+// { dg-options "-O2 -finline-functions -fno-ipa-icf" }
+
+import gcc.attributes;
+
+extern int t();
+
+void func()
+{
+ void nested_function() @noinline
+ {
+ t();
+ }
+ nested_function();
+}
+
+@noinline int var = 0; // { dg-warning ".noinline. attribute ignored" }
+
+// { dg-final { scan-assembler "nested_function" } }
new file mode 100644
@@ -0,0 +1,17 @@
+// { dg-do compile }
+// { dg-options "-O2 -finline-functions" }
+
+import gcc.attributes;
+
+int func(int x)
+{
+ int nested_function(int y, int z) @noipa
+ {
+ return y + z;
+ }
+ return nested_function(x, 0);
+}
+
+@noipa int var = 0; // { dg-warning ".noipa. attribute ignored" }
+
+// { dg-final { scan-assembler "nested_function" } }
new file mode 100644
@@ -0,0 +1,13 @@
+// { dg-do compile { target x86_64-*-linux* } }
+// { dg-options "-O2 -fno-pic" }
+
+import gcc.attributes;
+
+@noplt int func();
+
+@noplt int var = 0; // { dg-warning ".noplt. attribute ignored" }
+
+int main()
+{
+ return func();
+}
new file mode 100644
@@ -0,0 +1,48 @@
+// { dg-do compile }
+
+import gcc.attributes;
+
+int func()
+{
+ int return_zero() @optimize(0)
+ {
+ return 0;
+ }
+
+ int return_one() @optimize("0")
+ {
+ return 1;
+ }
+
+ int return_two() @optimize("s")
+ {
+ return 2;
+ }
+
+ int return_three() @optimize("O3")
+ {
+ return 3;
+ }
+
+ int return_four() @optimize("fast-math")
+ {
+ return 4;
+ }
+
+ return return_one + return_two + return_three + return_four;
+}
+
+@optimize(3)
+int var = 0; // { dg-warning ".optimize. attribute ignored" }
+
+@optimize("-f_")
+int bad_option() // { dg-warning "bad option .-f_. to attribute .optimize." }
+{
+ return 0;
+}
+
+@optimize("-z")
+int bad_option2() // { dg-warning "bad option .-z. to attribute .optimize." }
+{
+ return 0;
+}
new file mode 100644
@@ -0,0 +1,9 @@
+// { dg-do compile }
+
+import gcc.attributes;
+
+@optimize(-1)
+int non_negative() // { dg-error "argument to .-O. should be a non-negative integer" }
+{
+ return 0;
+}
new file mode 100644
@@ -0,0 +1,19 @@
+// { dg-do compile }
+// { dg-options "-O0 -fdump-tree-optimized-raw" }
+
+import gcc.attributes;
+
+double notfast(double x)
+{
+ return x * x * x * x * x * x * x * x;
+}
+
+// { dg-final { scan-tree-dump-times "mult_expr, _" 7 "optimized" } }
+
+@fastmath
+static double fast(double x)
+{
+ return x * x * x * x * x * x * x * x;
+}
+
+// { dg-final { scan-tree-dump-times "mult_expr, powmult_" 3 "optimized" } }
new file mode 100644
@@ -0,0 +1,45 @@
+// { dg-do compile }
+// { dg-options "-O3 -fdump-tree-optimized-raw" }
+
+import gcc.attributes;
+
+int glob1;
+int easily_inlinable(int i) { glob1 = i; return 2; }
+
+@optStrategy("none")
+int call_easily_inlinable(int i)
+{
+ return easily_inlinable(i);
+}
+
+// { dg-final { scan-tree-dump "gimple_call <easily_inlinable" "optimized" } }
+
+pragma(inline, true) int always_inline() { return 321; }
+
+@optStrategy("none")
+int call_always_inline()
+{
+ return always_inline();
+}
+
+// { dg-final { scan-tree-dump "gimple_call <always_inline" "optimized" } }
+
+int glob2;
+@optStrategy("none") void optnone_function(int i) { glob2 = i; }
+
+void call_optnone()
+{
+ optnone_function(1);
+}
+
+// { dg-final { scan-tree-dump "gimple_call <optnone_function" "optimized" } }
+
+@optStrategy("optsize")
+void optsize_fn()
+{
+}
+
+@optStrategy("minsize")
+void minsize_fn()
+{
+}
new file mode 100644
@@ -0,0 +1,18 @@
+// { dg-do compile }
+// { dg-options "-fdump-tree-optimized" }
+
+import gcc.attributes;
+
+int func(@restrict int ignored) // { dg-warning ".restrict. attribute ignored" }
+{
+ return 0;
+}
+
+int func(@restrict int *parm)
+{
+ return 0;
+}
+
+@restrict int var = 0; // { dg-warning ".restrict. attribute ignored" }
+
+// { dg-final { scan-tree-dump "restrict parm" "optimized" } }
new file mode 100644
@@ -0,0 +1,23 @@
+// { dg-do compile }
+// { dg-require-named-sections "" }
+
+import gcc.attributes;
+
+@section("types")
+struct S {} // { dg-warning ".section. attribute does not apply to types" }
+
+@attribute("section", 123)
+int f1(); // { dg-error "section attribute argument not a string constant" }
+
+int f2(@section("param") int a) // { dg-error "section attribute not allowed for .a." }
+{
+ @section("local") int v; // { dg-error "section attribute cannot be specified for local variables" }
+ return a;
+}
+
+@section("c1") void conflict();
+@section("c2") void conflict(); // { dg-error "section of .conflict. conflicts with previous declaration" }
+
+@section("c3")
+@section("c4")
+void conflict2(); // { dg-error "section of .conflict2. conflicts with previous declaration" }
new file mode 100644
@@ -0,0 +1,24 @@
+// { dg-do compile }
+// { dg-skip-if "only works for ELF targets" { *-*-darwin* *-*-aix* } }
+
+import gcc.attributes;
+
+@symver("type")
+struct S {} // { dg-warning ".symver. attribute does not apply to types" }
+
+@attribute("symver", 123)
+int f1(); // { dg-error ".symver. attribute argument not a string constant" }
+
+@symver("format")
+int f2() // { dg-error "symver attribute argument must have format .name@nodename'" }
+{ // { dg-error ".symver. attribute argument .format. must contain one or two .@." "" { target *-*-* } .-1 }
+ return 0;
+}
+
+int f3(@symver("param@VER_1") int param) // { dg-warning ".symver. attribute only applies to functions and variables" }
+{
+ return param;
+}
+
+@symver("extern@VER_2")
+extern int f4(); // { dg-error "symbol needs to be defined to have a version" }
new file mode 100644
@@ -0,0 +1,20 @@
+// { dg-do compile { target i?86*-*-* x86_64-*-* } }
+
+import gcc.attributes;
+
+@target("default")
+int foo() { return 1; }
+
+@target("arch=core2", "")
+int foo2() { return 2; } // { dg-warning "empty string in attribute .target." }
+
+@target("sse4.2", "", "")
+int foo3() { return 3; } // { dg-warning "empty string in attribute .target." }
+
+@target("default")
+int var = 0; // { dg-warning ".target. attribute ignored" }
+
+int main()
+{
+ return foo() + foo2() + foo3();
+}
new file mode 100644
@@ -0,0 +1,12 @@
+// { dg-do compile { target i?86*-*-* x86_64-*-* } }
+
+import gcc.attributes;
+
+@target_clones("default")
+int func() // { dg-warning "single .target_clones. attribute is ignored" }
+{
+ return 0;
+}
+
+@target_clones("default")
+int var = 0; // { dg-warning ".target_clones. attribute ignored" }
new file mode 100644
@@ -0,0 +1,16 @@
+// { dg-do compile }
+// { dg-options "-O2" }
+
+import gcc.attributes;
+
+int func()
+{
+ int nested_function() @used
+ {
+ return 1;
+ }
+ @used int var = 0; // { dg-warning ".used. attribute ignored" }
+ return var;
+}
+
+// { dg-final { scan-assembler "nested_function" } }
new file mode 100644
@@ -0,0 +1,16 @@
+// { dg-do compile }
+// { dg-options "-O2" }
+
+import gcc.attributes;
+
+int func()
+{
+ int nested_function() @assumeUsed
+ {
+ return 1;
+ }
+ @assumeUsed int var = 0; // { dg-warning ".used. attribute ignored" }
+ return var;
+}
+
+// { dg-final { scan-assembler "nested_function" } }
new file mode 100644
@@ -0,0 +1,14 @@
+// { dg-do compile }
+
+import gcc.attributes;
+
+pragma(inline, true)
+@weak int func() // { dg-warning "inline function .func. declared weak" }
+{
+ return 0;
+}
+
+int parm(@weak int a) // { dg-warning ".weak. attribute ignored" }
+{
+ return a;
+}
@@ -1,9 +1,9 @@
// https://bugzilla.gdcproject.org/show_bug.cgi?id=108
// { dg-do compile }
-import gcc.attribute;
+import gcc.attributes;
-@attribute("forceinline")
+@attribute("always_inline")
void forceinline108()
{
}
@@ -1,7 +1,7 @@
// https://bugzilla.gdcproject.org/show_bug.cgi?id=142
// { dg-do compile }
-import gcc.attribute;
+import gcc.attributes;
@attribute("noinline")
int test142a()()
new file mode 100644
@@ -0,0 +1,28 @@
+// Pretend to be the GDC attributes module.
+module gcc.attributes;
+
+immutable value_ignored = 42;
+
+enum type_symbol { _ }
+
+auto template_symbol(A...)(A arguments)
+{
+ return arguments;
+}
+
+struct struct_wrong_field
+{
+ int bad_field;
+}
+
+struct struct_void_init
+{
+ string name_field = "noinline";
+ int void_field = void;
+ string ignored;
+}
+
+struct unknown_attribute
+{
+ string name_field = "made up name";
+}
@@ -3,9 +3,9 @@
// { dg-options "-fdump-tree-optimized" }
// { dg-final { scan-tree-dump-times "sum_array \\(array\\)" 0 "optimized"} }
-import gcc.attribute;
+import gcc.attributes;
-@attribute("forceinline") int sum_array(int[] input);
+@attribute("always_inline") int sum_array(int[] input);
int sum_array(int[] input)
{
@@ -3,7 +3,7 @@
// { dg-options "-fdump-tree-optimized" }
// { dg-final { scan-tree-dump-times "sum_array \\(array\\)" 1 "optimized"} }
-import gcc.attribute;
+import gcc.attributes;
@attribute("noinline") int sum_array(int[] input);
@@ -2,8 +2,8 @@
// { dg-do compile }
// { dg-options "-Wattributes" }
-import gcc.attribute;
+import gcc.attributes;
-@attribute("forceinline") int sum_array(int[] input);
+@attribute("always_inline") int sum_array(int[] input);
@attribute("noinline") int sum_array(int[] input);
-// { dg-warning "ignoring attribute .noinline. because it conflicts with attribute .forceinline." "" { target *-*-* } .-1 }
+// { dg-warning "ignoring attribute .noinline. because it conflicts with attribute .always_inline." "" { target *-*-* } .-1 }
@@ -2,7 +2,7 @@
// { dg-do compile }
// { dg-options "-Wattributes" }
-import gcc.attribute;
+import gcc.attributes;
@attribute("foo") // { dg-warning "unknown attribute .foo." }
void f95173()
@@ -184,8 +184,8 @@ DRUNTIME_DSOURCES = core/atomic.d core/attribute.d core/bitop.d \
core/thread/threadbase.d core/thread/threadgroup.d core/thread/types.d \
core/time.d core/vararg.d core/volatile.d gc/bits.d gc/config.d \
gc/gcinterface.d gc/impl/conservative/gc.d gc/impl/manual/gc.d gc/os.d \
- gc/pooltable.d gc/proxy.d gcc/attribute.d gcc/backtrace.d \
- gcc/builtins.d gcc/deh.d gcc/emutls.d gcc/gthread.d \
+ gc/pooltable.d gc/proxy.d gcc/attribute.d gcc/attributes.d \
+ gcc/backtrace.d gcc/builtins.d gcc/deh.d gcc/emutls.d gcc/gthread.d \
gcc/sections/android.d gcc/sections/elf_shared.d gcc/sections/osx.d \
gcc/sections/package.d gcc/sections/win32.d gcc/sections/win64.d \
gcc/unwind/arm.d gcc/unwind/arm_common.d gcc/unwind/c6x.d \
@@ -209,11 +209,12 @@ am__objects_1 = core/atomic.lo core/attribute.lo core/bitop.lo \
core/thread/types.lo core/time.lo core/vararg.lo \
core/volatile.lo gc/bits.lo gc/config.lo gc/gcinterface.lo \
gc/impl/conservative/gc.lo gc/impl/manual/gc.lo gc/os.lo \
- gc/pooltable.lo gc/proxy.lo gcc/attribute.lo gcc/backtrace.lo \
- gcc/builtins.lo gcc/deh.lo gcc/emutls.lo gcc/gthread.lo \
- gcc/sections/android.lo gcc/sections/elf_shared.lo \
- gcc/sections/osx.lo gcc/sections/package.lo \
- gcc/sections/win32.lo gcc/sections/win64.lo gcc/unwind/arm.lo \
+ gc/pooltable.lo gc/proxy.lo gcc/attribute.lo gcc/attributes.lo \
+ gcc/backtrace.lo gcc/builtins.lo gcc/deh.lo gcc/emutls.lo \
+ gcc/gthread.lo gcc/sections/android.lo \
+ gcc/sections/elf_shared.lo gcc/sections/osx.lo \
+ gcc/sections/package.lo gcc/sections/win32.lo \
+ gcc/sections/win64.lo gcc/unwind/arm.lo \
gcc/unwind/arm_common.lo gcc/unwind/c6x.lo \
gcc/unwind/generic.lo gcc/unwind/package.lo gcc/unwind/pe.lo \
object.lo rt/aApply.lo rt/aApplyR.lo rt/aaA.lo rt/adi.lo \
@@ -816,8 +817,8 @@ DRUNTIME_DSOURCES = core/atomic.d core/attribute.d core/bitop.d \
core/thread/threadbase.d core/thread/threadgroup.d core/thread/types.d \
core/time.d core/vararg.d core/volatile.d gc/bits.d gc/config.d \
gc/gcinterface.d gc/impl/conservative/gc.d gc/impl/manual/gc.d gc/os.d \
- gc/pooltable.d gc/proxy.d gcc/attribute.d gcc/backtrace.d \
- gcc/builtins.d gcc/deh.d gcc/emutls.d gcc/gthread.d \
+ gc/pooltable.d gc/proxy.d gcc/attribute.d gcc/attributes.d \
+ gcc/backtrace.d gcc/builtins.d gcc/deh.d gcc/emutls.d gcc/gthread.d \
gcc/sections/android.d gcc/sections/elf_shared.d gcc/sections/osx.d \
gcc/sections/package.d gcc/sections/win32.d gcc/sections/win64.d \
gcc/unwind/arm.d gcc/unwind/arm_common.d gcc/unwind/c6x.d \
@@ -1209,6 +1210,7 @@ gcc/$(am__dirstamp):
@$(MKDIR_P) gcc
@: > gcc/$(am__dirstamp)
gcc/attribute.lo: gcc/$(am__dirstamp)
+gcc/attributes.lo: gcc/$(am__dirstamp)
gcc/backtrace.lo: gcc/$(am__dirstamp)
gcc/builtins.lo: gcc/$(am__dirstamp)
gcc/deh.lo: gcc/$(am__dirstamp)
@@ -20,14 +20,7 @@
// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
// <http://www.gnu.org/licenses/>.
+deprecated("Import gcc.attributes instead")
module gcc.attribute;
-private struct Attribute(A...)
-{
- A args;
-}
-
-auto attribute(A...)(A args) if (A.length > 0 && is(A[0] == string))
-{
- return Attribute!A(args);
-}
+public import gcc.attributes;
new file mode 100644
@@ -0,0 +1,605 @@
+// GNU D Compiler attribute support declarations.
+// Copyright (C) 2021 Free Software Foundation, Inc.
+
+// GCC is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3, 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.
+
+// Under Section 7 of GPL version 3, you are granted additional
+// permissions described in the GCC Runtime Library Exception, version
+// 3.1, as published by the Free Software Foundation.
+
+// You should have received a copy of the GNU General Public License and
+// a copy of the GCC Runtime Library Exception along with this program;
+// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
+// <http://www.gnu.org/licenses/>.
+
+module gcc.attributes;
+
+// Private helper templates.
+private struct Attribute(A...)
+{
+ A arguments;
+}
+
+private enum bool isStringValue(alias T) = is(typeof(T) == string);
+
+private enum bool isStringOrIntValue(alias T)
+ = is(typeof(T) == string) || is(typeof(T) == int);
+
+private template allSatisfy(alias F, T...)
+{
+ static if (T.length == 0)
+ enum allSatisfy = true;
+ else static if (T.length == 1)
+ enum allSatisfy = F!(T[0]);
+ else
+ {
+ enum allSatisfy = allSatisfy!(F, T[ 0 .. $/2])
+ && allSatisfy!(F, T[$/2 .. $ ]);
+ }
+}
+
+/**
+ * Generic entrypoint for applying GCC attributes to a function or type.
+ * There is no type checking done, as well as no deprecation path for
+ * attributes removed from the compiler. So the recommendation is to use any
+ , of the other UDAs available unless it is a target-specific attribute.
+ *
+ * Function attributes introduced by the @attribute UDA are used in the
+ * declaration of a function, followed by an attribute name string and
+ * any arguments separated by commas enclosed in parentheses.
+ *
+ * Example:
+ * ---
+ * import gcc.attributes;
+ *
+ * @attribute("regparm", 1) int func(int size);
+ * ---
+ */
+@system
+auto attribute(A...)(A arguments)
+ if (A.length > 0 && is(A[0] == string))
+{
+ return Attribute!A(arguments);
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// Supported common attributes exposed by GDC.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+/**
+ * The `@alloc_size` attribute may be applied to a function that returns a
+ * pointer and takes at least one argument of an integer or enumerated type.
+ * It indicates that the returned pointer points to memory whose size is given
+ * by the function argument at `sizeArgIdx`, or by the product of the arguments
+ * at `sizeArgIdx` and `numArgIdx`. Meaningful sizes are positive values less
+ * than `ptrdiff_t.max`. Unless `zeroBasedNumbering` is true, argument
+ * numbering starts at one for ordinary functions, and at two for non-static
+ * member functions.
+ *
+ * If `numArgIdx` is less than `0`, it is taken to mean there is no argument
+ * specifying the element count.
+ *
+ * Example:
+ * ---
+ * import gcc.attributes;
+ *
+ * @alloc_size(1) extern(C) void* malloc(size_t size);
+ * @alloc_size(3,2) extern(C) void* reallocarray(void *ptr, size_t nmemb,
+ * size_t size);
+ * @alloc_size(1,2) void* my_calloc(size_t element_size, size_t count,
+ * bool irrelevant);
+ * ---
+ */
+auto alloc_size(int sizeArgIdx)
+{
+ return attribute("alloc_size", sizeArgIdx);
+}
+
+/// ditto
+auto alloc_size(int sizeArgIdx, int numArgIdx)
+{
+ return attribute("alloc_size", sizeArgIdx, numArgIdx);
+}
+
+/// ditto
+auto alloc_size(int sizeArgIdx, int numArgIdx, bool zeroBasedNumbering)
+{
+ return attribute("alloc_size", sizeArgIdx, numArgIdx, zeroBasedNumbering);
+}
+
+auto alloc_size(A...)(A arguments)
+{
+ assert(false, "alloc_size attribute argument value is not an integer constant");
+}
+
+/**
+ * The `@always_inline` attribute inlines the function independent of any
+ * restrictions that otherwise apply to inlining. Failure to inline such a
+ * function is diagnosed as an error.
+ *
+ * Example:
+ * ---
+ * import gcc.attributes;
+ *
+ * @always_inline int func();
+ * ---
+ */
+enum always_inline = attribute("always_inline");
+
+/**
+ * The `@cold` attribute on functions is used to inform the compiler that the
+ * function is unlikely to be executed. The function is optimized for size
+ * rather than speed and on many targets it is placed into a special subsection
+ * of the text section so all cold functions appear close together, improving
+ * code locality of non-cold parts of program. The paths leading to calls of
+ * cold functions within code are considered to be cold too.
+ *
+ * Example:
+ * ---
+ * import gcc.attributes;
+ *
+ * @cold int func();
+ * ---
+ */
+enum cold = attribute("cold");
+
+/**
+ * The `@flatten` attribute is used to inform the compiler that every call
+ * inside this function should be inlined, if possible. Functions declared with
+ * attribute `@noinline` and similar are not inlined.
+ *
+ * Example:
+ * ---
+ * import gcc.attributes;
+ *
+ * @flatten int func();
+ * ---
+ */
+enum flatten = attribute("flatten");
+
+/**
+ * The `@no_icf` attribute prevents a functions from being merged with another
+ * semantically equivalent function.
+ *
+ * Example:
+ * ---
+ * import gcc.attributes;
+ *
+ * @no_icf int func();
+ * ---
+ */
+enum no_icf = attribute("no_icf");
+
+/**
+ * The `@noclone` attribute prevents a function from being considered for
+ * cloning - a mechanism that produces specialized copies of functions and
+ * which is (currently) performed by interprocedural constant propagation.
+ *
+ * Example:
+ * ---
+ * import gcc.attributes;
+ *
+ * @noclone int func();
+ * ---
+ */
+enum noclone = attribute("noclone");
+
+/**
+ * The `@noinline` attribute prevents a function from being considered for
+ * inlining. If the function does not have side effects, there are
+ * optimizations other than inlining that cause function calls to be optimized
+ * away, although the function call is live. To keep such calls from being
+ * optimized away, put `asm { ""; }` in the called function, to serve as a
+ * special side effect.
+ *
+ * Example:
+ * ---
+ * import gcc.attributes;
+ *
+ * @noinline int func();
+ * ---
+ */
+enum noinline = attribute("noinline");
+
+/**
+ * The `@noipa` attribute disables interprocedural optimizations between the
+ * function with this attribute and its callers, as if the body of the function
+ * is not available when optimizing callers and the callers are unavailable when
+ * optimizing the body. This attribute implies `@noinline`, `@noclone`, and
+ * `@no_icf` attributes. However, this attribute is not equivalent to a
+ * combination of other attributes, because its purpose is to suppress existing
+ * and future optimizations employing interprocedural analysis, including those
+ * that do not have an attribute suitable for disabling them individually.
+ *
+ * This attribute is supported mainly for the purpose of testing the compiler.
+ *
+ * Example:
+ * ---
+ * import gcc.attributes;
+ *
+ * @noipa int func();
+ * ---
+ */
+enum noipa = attribute("noipa");
+
+/**
+ * The `@optimize` attribute is used to specify that a function is to be
+ * compiled with different optimization options than specified on the command
+ * line. Valid `arguments` are constant non-negative integers and strings.
+ * Multiple arguments can be provided, separated by commas to specify multiple
+ * options. Each numeric argument specifies an optimization level. Each string
+ * argument that begins with the letter O refers to an optimization option such
+ * as `-O0` or `-Os`. Other options are taken as suffixes to the `-f` prefix
+ * jointly forming the name of an optimization option.
+ *
+ * Not every optimization option that starts with the `-f` prefix specified by
+ * the attribute necessarily has an effect on the function. The `@optimize`
+ * attribute should be used for debugging purposes only. It is not suitable in
+ * production code.
+ *
+ * Example:
+ * ---
+ * import gcc.attributes;
+ *
+ * @optimize(2) double fn0(double x);
+ * @optimize("2") double fn1(double x);
+ * @optimize("s") double fn2(double x);
+ * @optimize("Ofast") double fn3(double x);
+ * @optimize("-O2") double fn4(double x);
+ * @optimize("tree-vectorize") double fn5(double x);
+ * @optimize("-ftree-vectorize") double fn6(double x);
+ * @optimize("no-finite-math-only", 3) double fn7(double x);
+ * ---
+ */
+auto optimize(A...)(A arguments)
+ if (allSatisfy!(isStringOrIntValue, arguments))
+{
+ return attribute("optimize", arguments);
+}
+
+auto optimize(A...)(A arguments)
+ if (!allSatisfy!(isStringOrIntValue, arguments))
+{
+ assert(false, "optimize attribute argument not a string or integer constant");
+}
+
+/**
+ * The `@restrict` attribute specifies that a function parameter is to be
+ * restrict-qualified in the C99 sense of the term. The parameter needs to
+ * boil down to either a pointer or reference type, such as a D pointer,
+ * class reference, or a `ref` parameter.
+ *
+ * Example:
+ * ---
+ * import gcc.attributes;
+ *
+ * void func(@restrict ref const float[16] array);
+ * ---
+ */
+enum restrict = attribute("restrict");
+
+/**
+ * The `@section` attribute specifies that a function lives in a particular
+ * section. For when you need certain particular functions to appear in
+ * special sections.
+ *
+ * Some file formats do not support arbitrary sections so the section attribute
+ * is not available on all platforms. If you need to map the entire contents
+ * of a module to a particular section, consider using the facilities of the
+ * linker instead.
+ *
+ * Example:
+ * ---
+ * import gcc.attributes;
+ *
+ * @section("bar") extern void func();
+ * ---
+ */
+auto section(string sectionName)
+{
+ return attribute("section", sectionName);
+}
+
+auto section(A...)(A arguments)
+{
+ assert(false, "section attribute argument not a string constant");
+}
+
+/**
+ * The `@symver` attribute creates a symbol version on ELF targets. The syntax
+ * of the string parameter is `name@nodename`. The `name` part of the parameter
+ * is the actual name of the symbol by which it will be externally referenced.
+ * The `nodename` portion should be the name of a node specified in the version
+ * script supplied to the linker when building a shared library. Versioned
+ * symbol must be defined and must be exported with default visibility.
+ *
+ * Finally if the parameter is `name@@nodename` then in addition to creating a
+ * symbol version (as if `name@nodename` was used) the version will be also used
+ * to resolve `name` by the linker.
+ *
+ * Example:
+ * ---
+ * import gcc.attributes;
+ *
+ * @symver("foo@VERS_1") int foo_v1();
+ * ---
+ */
+auto symver(A...)(A arguments)
+ if (allSatisfy!(isStringValue, arguments))
+{
+ return attribute("symver", arguments);
+}
+
+auto symver(A...)(A arguments)
+ if (!allSatisfy!(isStringValue, arguments))
+{
+ assert(false, "symver attribute argument not a string constant");
+}
+
+/**
+ * The `@target` attribute is used to specify that a function is to be
+ * compiled with different target options than specified on the command line.
+ * One or more strings can be provided as arguments, separated by commas to
+ * specify multiple options. Each string consists of one or more
+ * comma-separated suffixes to the `-m` prefix jointly forming the name of a
+ * machine-dependent option.
+ *
+ * The target attribute can be used for instance to have a function compiled
+ * with a different ISA (instruction set architecture) than the default.
+ *
+ * The options supported are specific to each target.
+ *
+ * Example:
+ * ---
+ * import gcc.attributes;
+ *
+ * @target("arch=core2") void core2_func();
+ * @target("sse3") void sse3_func();
+ * ---
+ */
+auto target(A...)(A arguments)
+ if (allSatisfy!(isStringValue, arguments))
+{
+ return attribute("target", arguments);
+}
+
+auto target(A...)(A arguments)
+ if (!allSatisfy!(isStringValue, arguments))
+{
+ assert(false, "target attribute argument not a string constant");
+}
+
+/**
+ * The `@target_clones` attribute is used to specify that a function be cloned
+ * into multiple versions compiled with different target `options` than
+ * specified on the command line. The supported options and restrictions are
+ * the same as for `@target` attribute.
+ *
+ * It also creates a resolver function that dynamically selects a clone suitable
+ * for current architecture. The resolver is created only if there is a usage
+ * of a function with `@target_clones` attribute.
+ *
+ * Example:
+ * ---
+ * import gcc.attributes;
+ *
+ * @target_clones("sse4.1,avx,default") double func(double x);
+ * ---
+ */
+auto target_clones(A...)(A arguments)
+ if (allSatisfy!(isStringValue, arguments))
+{
+ return attribute("target_clones", arguments);
+}
+
+auto target_clones(A...)(A arguments)
+ if (!allSatisfy!(isStringValue, arguments))
+{
+ assert(false, "target attribute argument not a string constant");
+}
+
+/**
+ * The `@used` attribute, annotated to a function, means that code must be
+ * emitted for the function even if it appears that the function is not
+ * referenced. This is useful, for example, when the function is referenced
+ * only in inline assembly.
+ *
+ * Example:
+ * ---
+ * import gcc.attributes;
+ *
+ * @used __gshared int var = 0x1000;
+ * ---
+ */
+enum used = attribute("used");
+
+/**
+ * The `@weak` attribute causes a declaration of an external symbol to be
+ * emitted as a weak symbol rather than a global. This is primarily useful in
+ * defining library functions that can be overridden in user code, though it can
+ * also be used with non-function declarations. The overriding symbol must have
+ * the same type as the weak symbol. In addition, if it designates a variable
+ * it must also have the same size and alignment as the weak symbol.
+ *
+ * Weak symbols are supported for ELF targets, and also for a.out targets when
+ * using the GNU assembler and linker.
+ *
+ * Example:
+ * ---
+ * import gcc.attributes;
+ *
+ * @weak int func() { return 1; }
+ * ---
+ */
+enum weak = attribute("weak");
+
+/**
+ * The `@noplt` attribute is the counterpart to option `-fno-plt`. Calls to
+ * functions marked with this attribute in position-independent code do not use
+ * the PLT in position-independent code.
+ *
+ * In position-dependant code, a few targets also convert call to functions
+ * that are marked to not use the PLT to use the GOT instead.
+ *
+ * Example:
+ * ---
+ * import gcc.attributes;
+ *
+ * @noplt int func();
+ *
+ * ---
+ */
+enum noplt = attribute("noplt");
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// Attributes defined for compatibility with LDC.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+/**
+ * Specifies that the function returns `null` or a pointer to at least a
+ * certain number of allocated bytes. `sizeArgIdx` and `numArgIdx` specify
+ * the 0-based index of the function arguments that should be used to calculate
+ * the number of bytes returned.
+ *
+ * Example:
+ * ---
+ * import gcc.attributes;
+ *
+ * @allocSize(0) extern(C) void* malloc(size_t size);
+ * @allocSize(2,1) extern(C) void* reallocarray(void *ptr, size_t nmemb,
+ * size_t size);
+ * @allocSize(0,1) void* my_calloc(size_t element_size, size_t count,
+ * bool irrelevant);
+ * ---
+ */
+auto allocSize(int sizeArgIdx, int numArgIdx = int.min)
+{
+ return alloc_size(sizeArgIdx, numArgIdx, true);
+}
+
+auto allocSize(A...)(A arguments)
+{
+ assert(false, "allocSize attribute argument value is not an integer constant");
+}
+
+/**
+ * When applied to a global symbol, the compiler, assembler, and linker are
+ * required to treat the symbol as if there is a reference to the symbol that
+ * it cannot see (which is why they have to be named). For example, it
+ * prevents the deletion by the linker of an unreferenced symbol.
+ *
+ * Example:
+ * ---
+ * import gcc.attributes;
+ *
+ * @assumeUsed __gshared int var = 0x1000;
+ * ---
+ */
+alias assumeUsed = used;
+
+/// This attribute has no effect.
+enum dynamicCompile = false;
+
+/// ditto
+enum dynamicCompileConst = false;
+
+/// ditto
+enum dynamicCompileEmit = false;
+
+/**
+ * Explicitly sets "fast-math" for a function, enabling aggressive math
+ * optimizations. These optimizations may dramatically change the outcome of
+ * floating point calculations (e.g. because of reassociation).
+ *
+ * Example:
+ * ---
+ * import gcc.attributes;
+ *
+ * @fastmath
+ * double dot(double[] a, double[] b) {
+ * double s = 0;
+ * foreach(size_t i; 0..a.length)
+ * {
+ * // will result in vectorized fused-multiply-add instructions
+ * s += a * b;
+ * }
+ * return s;
+ * }
+ * ---
+ */
+enum fastmath = optimize("Ofast");
+
+/**
+ * Adds GCC's "naked" attribute to a function, disabling function prologue /
+ * epilogue emission.
+ * Intended to be used in combination with basic `asm` statement. While using
+ * extended `asm` or a mixture of basic `asm` and D code may appear to work,
+ * they cannot be depended upon to work reliably and are not supported.
+ *
+ * Example:
+ * ---
+ * import gcc.attributes;
+ *
+ * @naked void abort() {
+ * asm { "ud2"; }
+ * }
+ * ---
+ */
+enum naked = attribute("naked");
+
+/**
+ * Sets the optimization strategy for a function.
+ * Valid strategies are "none", "optsize", "minsize". The strategies are
+ * mutually exclusive.
+ *
+ * Example:
+ * ---
+ * import gcc.attributes;
+ *
+ * @optStrategy("none")
+ * int func() {
+ * return call();
+ * }
+ * ---
+ */
+auto optStrategy(string strategy)
+{
+ if (strategy == "none")
+ return optimize("O0");
+ else if (strategy == "optsize" || strategy == "minsize")
+ return optimize("Os");
+ else
+ {
+ assert(false, "unrecognized parameter `" ~ strategy
+ ~ "` for `gcc.attribute.optStrategy`");
+ }
+}
+
+auto optStrategy(A...)(A arguments)
+{
+ assert(false, "optStrategy attribute argument value is not a string constant");
+}
+
+/**
+ * When applied to a function, specifies that the function should be optimzed
+ * by Graphite, GCC's polyhedral optimizer. Useful for optimizing loops for
+ * data locality, vectorization and parallelism.
+ *
+ * Experimental!
+ *
+ * Only effective when GDC was built with ISL included.
+ */
+enum polly = optimize("loop-parallelize-all", "loop-nest-optimize");
@@ -28,7 +28,7 @@ import gcc.unwind;
import gcc.unwind.pe;
import gcc.builtins;
import gcc.config;
-import gcc.attribute;
+import gcc.attributes;
extern(C)
{