Ada already has support for the strub attributes stubbed-out, and the
front-end code already has support for them and their effects in the
type system.

for  gcc/ChangeLog

        * attribs.cc: Include ipa-strub.h.
        (decl_attributes): Support applying attributes to function
        type, rather than pointer type, at handler's request.
        (comp_type_attributes): Combine strub_comptypes and target
        comp_type results.

for  gcc/c-family/ChangeLog

        * c-attribs.cc: Include ipa-strub.h.
        (handle_strub_attribute): New.
        (c_common_attribute_table): Add strub.

for  gcc/ada/ChangeLog

        * gcc-interface/utils.cc: Include ipa-strub.h.
        (handle_strub_attribute): New.
        (gnat_internal_attribute_table): Add strub.

diff --git a/gcc/attribs.cc b/gcc/attribs.cc
index fb89616ff296b..d559cfc1b9f4e 100644
--- a/gcc/attribs.cc
+++ b/gcc/attribs.cc
@@ -27,6 +27,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "diagnostic-core.h"
 #include "attribs.h"
 #include "fold-const.h"
+#include "ipa-strub.h"
 #include "stor-layout.h"
 #include "langhooks.h"
 #include "plugin.h"
@@ -774,12 +775,11 @@ decl_attributes (tree *node, tree attributes, int flags,
          flags &= ~(int) ATTR_FLAG_TYPE_IN_PLACE;
        }
 
-      if (spec->function_type_required && TREE_CODE (*anode) != FUNCTION_TYPE
-         && TREE_CODE (*anode) != METHOD_TYPE)
+      if (spec->function_type_required
+         && !FUNC_OR_METHOD_TYPE_P (*anode))
        {
          if (TREE_CODE (*anode) == POINTER_TYPE
-             && (TREE_CODE (TREE_TYPE (*anode)) == FUNCTION_TYPE
-                 || TREE_CODE (TREE_TYPE (*anode)) == METHOD_TYPE))
+             && FUNC_OR_METHOD_TYPE_P (TREE_TYPE (*anode)))
            {
              /* OK, this is a bit convoluted.  We can't just make a copy
                 of the pointer type and modify its TREE_TYPE, because if
@@ -887,7 +887,24 @@ decl_attributes (tree *node, tree attributes, int flags,
              TYPE_NAME (tt) = *node;
            }
 
-         *anode = cur_and_last_decl[0];
+         if (*anode != cur_and_last_decl[0])
+           {
+             /* Even if !spec->function_type_required, allow the attribute
+                handler to request the attribute to be applied to the function
+                type, rather than to the function pointer type, by setting
+                cur_and_last_decl[0] to the function type.  */
+             if (!fn_ptr_tmp
+                 && POINTER_TYPE_P (*anode)
+                 && TREE_TYPE (*anode) == cur_and_last_decl[0]
+                 && FUNC_OR_METHOD_TYPE_P (TREE_TYPE (*anode)))
+               {
+                 fn_ptr_tmp = TREE_TYPE (*anode);
+                 fn_ptr_quals = TYPE_QUALS (*anode);
+                 anode = &fn_ptr_tmp;
+               }
+             *anode = cur_and_last_decl[0];
+           }
+
          if (ret == error_mark_node)
            {
              warning (OPT_Wattributes, "%qE attribute ignored", name);
@@ -1491,9 +1508,20 @@ comp_type_attributes (const_tree type1, const_tree type2)
   if ((lookup_attribute ("nocf_check", TYPE_ATTRIBUTES (type1)) != NULL)
       ^ (lookup_attribute ("nocf_check", TYPE_ATTRIBUTES (type2)) != NULL))
     return 0;
+  int strub_ret = strub_comptypes (CONST_CAST_TREE (type1),
+                                  CONST_CAST_TREE (type2));
+  if (strub_ret == 0)
+    return strub_ret;
   /* As some type combinations - like default calling-convention - might
      be compatible, we have to call the target hook to get the final result.  
*/
-  return targetm.comp_type_attributes (type1, type2);
+  int target_ret = targetm.comp_type_attributes (type1, type2);
+  if (target_ret == 0)
+    return target_ret;
+  if (strub_ret == 2 || target_ret == 2)
+    return 2;
+  if (strub_ret == 1 && target_ret == 1)
+    return 1;
+  gcc_unreachable ();
 }
 
 /* PREDICATE acts as a function of type:
diff --git a/gcc/c-family/c-attribs.cc b/gcc/c-family/c-attribs.cc
index e4f1d3542f378..08c7d71f827a2 100644
--- a/gcc/c-family/c-attribs.cc
+++ b/gcc/c-family/c-attribs.cc
@@ -41,6 +41,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "common/common-target.h"
 #include "langhooks.h"
 #include "tree-inline.h"
+#include "ipa-strub.h"
 #include "toplev.h"
 #include "tree-iterator.h"
 #include "opts.h"
@@ -69,6 +70,7 @@ static tree handle_asan_odr_indicator_attribute (tree *, 
tree, tree, int,
 static tree handle_stack_protect_attribute (tree *, tree, tree, int, bool *);
 static tree handle_no_stack_protector_function_attribute (tree *, tree,
                                                        tree, int, bool *);
+static tree handle_strub_attribute (tree *, tree, tree, int, bool *);
 static tree handle_noinline_attribute (tree *, tree, tree, int, bool *);
 static tree handle_noclone_attribute (tree *, tree, tree, int, bool *);
 static tree handle_nocf_check_attribute (tree *, tree, tree, int, bool *);
@@ -314,6 +316,8 @@ const struct attribute_spec c_common_attribute_table[] =
   { "no_stack_protector",     0, 0, true, false, false, false,
                              handle_no_stack_protector_function_attribute,
                              attr_stack_protect_exclusions },
+  { "strub",                 0, 1, false, true, false, true,
+                             handle_strub_attribute, NULL },
   { "noinline",               0, 0, true,  false, false, false,
                              handle_noinline_attribute,
                              attr_noinline_exclusions },
@@ -1327,6 +1331,84 @@ handle_noipa_attribute (tree *node, tree name, tree, 
int, bool *no_add_attrs)
   return NULL_TREE;
 }
 
+/* Handle a "strub" attribute; arguments as in
+   struct attribute_spec.handler.  */
+
+static tree
+handle_strub_attribute (tree *node, tree name,
+                       tree args,
+                       int ARG_UNUSED (flags), bool *no_add_attrs)
+{
+  bool enable = true;
+
+  if (args && FUNCTION_POINTER_TYPE_P (*node))
+    *node = TREE_TYPE (*node);
+
+  if (args && FUNC_OR_METHOD_TYPE_P (*node))
+    {
+      switch (strub_validate_fn_attr_parm (TREE_VALUE (args)))
+       {
+       case 1:
+       case 2:
+         enable = true;
+         break;
+
+       case 0:
+         warning (OPT_Wattributes,
+                  "%qE attribute ignored because of argument %qE",
+                  name, TREE_VALUE (args));
+         *no_add_attrs = true;
+         enable = false;
+         break;
+
+       case -1:
+       case -2:
+         enable = false;
+         break;
+
+       default:
+         gcc_unreachable ();
+       }
+
+      args = TREE_CHAIN (args);
+    }
+
+  if (args)
+    {
+      warning (OPT_Wattributes,
+              "ignoring attribute %qE because of excess arguments"
+              " starting at %qE",
+              name, TREE_VALUE (args));
+      *no_add_attrs = true;
+      enable = false;
+    }
+
+  /* Warn about unmet expectations that the strub attribute works like a
+     qualifier.  ??? Could/should we extend it to the element/field types
+     here?  */
+  if (TREE_CODE (*node) == ARRAY_TYPE
+      || VECTOR_TYPE_P (*node)
+      || TREE_CODE (*node) == COMPLEX_TYPE)
+    warning (OPT_Wattributes,
+            "attribute %qE does not apply to elements"
+            " of non-scalar type %qT",
+            name, *node);
+  else if (RECORD_OR_UNION_TYPE_P (*node))
+    warning (OPT_Wattributes,
+            "attribute %qE does not apply to fields"
+            " of aggregate type %qT",
+            name, *node);
+
+  /* If we see a strub-enabling attribute, and we're at the default setting,
+     implicitly or explicitly, note that the attribute was seen, so that we can
+     reduce the compile-time overhead to nearly zero when the strub feature is
+     not used.  */
+  if (enable && flag_strub < -2)
+    flag_strub += 2;
+
+  return NULL_TREE;
+}
+
 /* Handle a "noinline" attribute; arguments as in
    struct attribute_spec.handler.  */
 
diff --git a/gcc/ada/gcc-interface/utils.cc b/gcc/ada/gcc-interface/utils.cc
index a57143021a79e..36b1345530d71 100644
--- a/gcc/ada/gcc-interface/utils.cc
+++ b/gcc/ada/gcc-interface/utils.cc
@@ -39,6 +39,7 @@
 #include "varasm.h"
 #include "toplev.h"
 #include "opts.h"
+#include "ipa-strub.h"
 #include "output.h"
 #include "debug.h"
 #include "convert.h"
@@ -6601,9 +6602,77 @@ handle_no_stack_protector_attribute (tree *node, tree 
name, tree, int,
    struct attribute_spec.handler.  */
 
 static tree
-handle_strub_attribute (tree *, tree, tree, int, bool *no_add_attrs)
+handle_strub_attribute (tree *node, tree name,
+                       tree args,
+                       int ARG_UNUSED (flags), bool *no_add_attrs)
 {
-  *no_add_attrs = true;
+  bool enable = true;
+
+  if (args && FUNCTION_POINTER_TYPE_P (*node))
+    *node = TREE_TYPE (*node);
+
+  if (args && FUNC_OR_METHOD_TYPE_P (*node))
+    {
+      switch (strub_validate_fn_attr_parm (TREE_VALUE (args)))
+       {
+       case 1:
+       case 2:
+         enable = true;
+         break;
+
+       case 0:
+         warning (OPT_Wattributes,
+                  "%qE attribute ignored because of argument %qE",
+                  name, TREE_VALUE (args));
+         *no_add_attrs = true;
+         enable = false;
+         break;
+
+       case -1:
+       case -2:
+         enable = false;
+         break;
+
+       default:
+         gcc_unreachable ();
+       }
+
+      args = TREE_CHAIN (args);
+    }
+
+  if (args)
+    {
+      warning (OPT_Wattributes,
+              "ignoring attribute %qE because of excess arguments"
+              " starting at %qE",
+              name, TREE_VALUE (args));
+      *no_add_attrs = true;
+      enable = false;
+    }
+
+  /* Warn about unmet expectations that the strub attribute works like a
+     qualifier.  ??? Could/should we extend it to the element/field types
+     here?  */
+  if (TREE_CODE (*node) == ARRAY_TYPE
+      || VECTOR_TYPE_P (*node)
+      || TREE_CODE (*node) == COMPLEX_TYPE)
+    warning (OPT_Wattributes,
+            "attribute %qE does not apply to elements"
+            " of non-scalar type %qT",
+            name, *node);
+  else if (RECORD_OR_UNION_TYPE_P (*node))
+    warning (OPT_Wattributes,
+            "attribute %qE does not apply to fields"
+            " of aggregate type %qT",
+            name, *node);
+
+  /* If we see a strub-enabling attribute, and we're at the default setting,
+     implicitly or explicitly, note that the attribute was seen, so that we can
+     reduce the compile-time overhead to nearly zero when the strub feature is
+     not used.  */
+  if (enable && flag_strub < -2)
+    flag_strub += 2;
+
   return NULL_TREE;
 }
 

-- 
Alexandre Oliva, happy hacker                https://FSFLA.org/blogs/lxo/
   Free Software Activist                       GNU Toolchain Engineer
Disinformation flourishes because many people care deeply about injustice
but very few check the facts.  Ask me about <https://stallmansupport.org>

Reply via email to