Don't build insn-extract.o with rtl checking
[gcc.git] / gcc / attribs.c
index de34918919b891d6e4400b087b38a44272c09e92..a6f6b70e39e199a9b08e943bb9598bf4d5b15da7 100644 (file)
@@ -1,5 +1,5 @@
 /* Functions dealing with attribute handling, used by most front ends.
-   Copyright (C) 1992-2019 Free Software Foundation, Inc.
+   Copyright (C) 1992-2020 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -17,6 +17,7 @@ You should have received a copy of the GNU General Public License
 along with GCC; see the file COPYING3.  If not see
 <http://www.gnu.org/licenses/>.  */
 
+#define INCLUDE_STRING
 #include "config.h"
 #include "system.h"
 #include "coretypes.h"
@@ -25,6 +26,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "stringpool.h"
 #include "diagnostic-core.h"
 #include "attribs.h"
+#include "fold-const.h"
 #include "stor-layout.h"
 #include "langhooks.h"
 #include "plugin.h"
@@ -32,6 +34,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "hash-set.h"
 #include "diagnostic.h"
 #include "pretty-print.h"
+#include "tree-pretty-print.h"
 #include "intl.h"
 
 /* Table of the tables of attributes (common, language, format, machine)
@@ -593,21 +596,6 @@ decl_attributes (tree *node, tree attributes, int flags,
        }
       gcc_assert (is_attribute_p (spec->name, name));
 
-      if (TYPE_P (*node)
-         && cxx11_attr_p
-         && !(flags & ATTR_FLAG_TYPE_IN_PLACE))
-       {
-         /* This is a c++11 attribute that appertains to a
-            type-specifier, outside of the definition of, a class
-            type.  Ignore it.  */
-         auto_diagnostic_group d;
-         if (warning (OPT_Wattributes, "attribute ignored"))
-           inform (input_location,
-                   "an attribute that appertains to a type-specifier "
-                   "is ignored");
-         continue;
-       }
-
       if (spec->decl_required && !DECL_P (*anode))
        {
          if (flags & ((int) ATTR_FLAG_DECL_NEXT
@@ -692,7 +680,8 @@ decl_attributes (tree *node, tree attributes, int flags,
         reject incompatible attributes.  */
       bool built_in = flags & ATTR_FLAG_BUILT_IN;
       if (spec->exclude
-         && (flag_checking || !built_in))
+         && (flag_checking || !built_in)
+         && !error_operand_p (last_decl))
        {
          /* Always check attributes on user-defined functions.
             Check them on built-ins only when -fchecking is set.
@@ -721,10 +710,16 @@ decl_attributes (tree *node, tree attributes, int flags,
          int cxx11_flag = (cxx11_attr_p ? ATTR_FLAG_CXX11 : 0);
 
          /* Pass in an array of the current declaration followed
-            by the last pushed/merged declaration if  one exists.
+            by the last pushed/merged declaration if one exists.
+            For calls that modify the type attributes of a DECL
+            and for which *ANODE is *NODE's type, also pass in
+            the DECL as the third element to use in diagnostics.
             If the handler changes CUR_AND_LAST_DECL[0] replace
             *ANODE with its value.  */
-         tree cur_and_last_decl[] = { *anode, last_decl };
+         tree cur_and_last_decl[3] = { *anode, last_decl };
+         if (anode != node && DECL_P (*node))
+           cur_and_last_decl[2] = *node;
+
          tree ret = (spec->handler) (cur_and_last_decl, name, args,
                                      flags|cxx11_flag, &no_add_attrs);
 
@@ -2031,6 +2026,289 @@ maybe_diag_alias_attributes (tree alias, tree target)
     }
 }
 
+/* Initialize a mapping RWM for a call to a function declared with
+   attribute access in ATTRS.  Each attribute positional operand
+   inserts one entry into the mapping with the operand number as
+   the key.  */
+
+void
+init_attr_rdwr_indices (rdwr_map *rwm, tree attrs)
+{
+  if (!attrs)
+    return;
+
+  for (tree access = attrs;
+       (access = lookup_attribute ("access", access));
+       access = TREE_CHAIN (access))
+    {
+      /* The TREE_VALUE of an attribute is a TREE_LIST whose TREE_VALUE
+        is the attribute argument's value.  */
+      tree mode = TREE_VALUE (access);
+      if (!mode)
+       return;
+
+      /* The (optional) list of VLA bounds.  */
+      tree vblist = TREE_CHAIN (mode);
+      if (vblist)
+       vblist = TREE_VALUE (vblist);
+
+      mode = TREE_VALUE (mode);
+      if (TREE_CODE (mode) != STRING_CST)
+       continue;
+      gcc_assert (TREE_CODE (mode) == STRING_CST);
+
+      for (const char *m = TREE_STRING_POINTER (mode); *m; )
+       {
+         attr_access acc = { };
+
+         /* Skip the internal-only plus sign.  */
+         if (*m == '+')
+           ++m;
+
+         acc.str = m;
+         acc.mode = acc.from_mode_char (*m);
+         acc.sizarg = UINT_MAX;
+
+         const char *end;
+         acc.ptrarg = strtoul (++m, const_cast<char**>(&end), 10);
+         m = end;
+
+         if (*m == '[')
+           {
+             /* Forms containing the square bracket are internal-only
+                (not specified by an attribute declaration), and used
+                for various forms of array and VLA parameters.  */
+             acc.internal_p = true;
+
+             /* Search to the closing bracket and look at the preceding
+                code: it determines the form of the most significant
+                bound of the array.  Others prior to it encode the form
+                of interior VLA bounds.  They're not of interest here.  */
+             end = strchr (m, ']');
+             const char *p = end;
+             gcc_assert (p);
+
+             while (ISDIGIT (p[-1]))
+               --p;
+
+             if (ISDIGIT (*p))
+               {
+                 /* A digit denotes a constant bound (as in T[3]).  */
+                 acc.static_p = p[-1] == 's';
+                 acc.minsize = strtoull (p, NULL, 10);
+               }
+             else if (' ' == p[-1])
+               {
+                 /* A space denotes an ordinary array of unspecified bound
+                    (as in T[]).  */
+                 acc.minsize = 0;
+               }
+             else if ('*' == p[-1] || '$' == p[-1])
+               {
+                 /* An asterisk denotes a VLA.  When the closing bracket
+                    is followed by a comma and a dollar sign its bound is
+                    on the list.  Otherwise it's a VLA with an unspecified
+                    bound.  */
+                 acc.static_p = p[-2] == 's';
+                 acc.minsize = HOST_WIDE_INT_M1U;
+               }
+
+             m = end + 1;
+           }
+
+         if (*m == ',')
+           {
+             ++m;
+             do
+               {
+                 if (*m == '$')
+                   {
+                     ++m;
+                     if (!acc.size)
+                       {
+                         /* Extract the list of VLA bounds for the current
+                            parameter, store it in ACC.SIZE, and advance
+                            to the list of bounds for the next VLA parameter.
+                         */
+                         acc.size = TREE_VALUE (vblist);
+                         vblist = TREE_CHAIN (vblist);
+                       }
+                   }
+
+                 if (ISDIGIT (*m))
+                   {
+                     /* Extract the positional argument.  It's absent
+                        for VLAs whose bound doesn't name a function
+                        parameter.  */
+                     unsigned pos = strtoul (m, const_cast<char**>(&end), 10);
+                     if (acc.sizarg == UINT_MAX)
+                       acc.sizarg = pos;
+                     m = end;
+                   }
+               }
+             while (*m == '$');
+           }
+
+         acc.end = m;
+
+         bool existing;
+         auto &ref = rwm->get_or_insert (acc.ptrarg, &existing);
+         if (existing)
+           {
+             /* Merge the new spec with the existing.  */
+             if (acc.minsize == HOST_WIDE_INT_M1U)
+               ref.minsize = HOST_WIDE_INT_M1U;
+
+             if (acc.sizarg != UINT_MAX)
+               ref.sizarg = acc.sizarg;
+
+             if (acc.mode)
+               ref.mode = acc.mode;
+           }
+         else
+           ref = acc;
+
+         /* Unconditionally add an entry for the required pointer
+            operand of the attribute, and one for the optional size
+            operand when it's specified.  */
+         if (acc.sizarg != UINT_MAX)
+           rwm->put (acc.sizarg, acc);
+       }
+    }
+}
+
+/* Return the access specification for a function parameter PARM
+   or null if the current function has no such specification.  */
+
+attr_access *
+get_parm_access (rdwr_map &rdwr_idx, tree parm,
+                tree fndecl /* = current_function_decl */)
+{
+  tree fntype = TREE_TYPE (fndecl);
+  init_attr_rdwr_indices (&rdwr_idx, TYPE_ATTRIBUTES (fntype));
+
+  if (rdwr_idx.is_empty ())
+    return NULL;
+
+  unsigned argpos = 0;
+  tree fnargs = DECL_ARGUMENTS (fndecl);
+  for (tree arg = fnargs; arg; arg = TREE_CHAIN (arg), ++argpos)
+    if (arg == parm)
+      return rdwr_idx.get (argpos);
+
+  return NULL;
+}
+
+/* Return the internal representation as STRING_CST.  Internal positional
+   arguments are zero-based.  */
+
+tree
+attr_access::to_internal_string () const
+{
+  return build_string (end - str, str);
+}
+
+/* Return the human-readable representation of the external attribute
+   specification (as it might appear in the source code) as STRING_CST.
+   External positional arguments are one-based.  */
+
+tree
+attr_access::to_external_string () const
+{
+  char buf[80];
+  gcc_assert (mode != access_deferred);
+  int len = snprintf (buf, sizeof buf, "access (%s, %u",
+                     mode_names[mode], ptrarg + 1);
+  if (sizarg != UINT_MAX)
+    len += snprintf (buf + len, sizeof buf - len, ", %u", sizarg + 1);
+  strcpy (buf + len, ")");
+  return build_string (len + 2, buf);
+}
+
+/* Return the number of specified VLA bounds and set *nunspec to
+   the number of unspecified ones (those designated by [*]).  */
+
+unsigned
+attr_access::vla_bounds (unsigned *nunspec) const
+{
+  *nunspec = 0;
+  for (const char* p = strrchr (str, ']'); p && *p != '['; --p)
+    if (*p == '*')
+      ++*nunspec;
+  return list_length (size);
+}
+
+
+/* Defined in attr_access.  */
+constexpr char attr_access::mode_chars[];
+constexpr char attr_access::mode_names[][11];
+
+/* Format an array, including a VLA, pointed to by TYPE and used as
+   a function parameter as a human-readable string.  ACC describes
+   an access to the parameter and is used to determine the outermost
+   form of the array including its bound which is otherwise obviated
+   by its decay to pointer.  Return the formatted string.  */
+
+std::string
+attr_access::array_as_string (tree type) const
+{
+  std::string typstr;
+
+  if (type == error_mark_node)
+    return std::string ();
+
+  if (this->str)
+    {
+      /* For array parameters (but not pointers) create a temporary array
+        type that corresponds to the form of the parameter including its
+        qualifiers even though they apply to the pointer, not the array
+        type.  */
+      const bool vla_p = minsize == HOST_WIDE_INT_M1U;
+      tree eltype = TREE_TYPE (type);
+      tree index_type = NULL_TREE;
+
+      if (minsize == HOST_WIDE_INT_M1U)
+       {
+         /* Determine if this is a VLA (an array whose most significant
+            bound is nonconstant and whose access string has "$]" in it)
+            extract the bound expression from SIZE.  */
+         const char *p = end;
+         for ( ; p != str && *p-- != ']'; );
+         if (*p == '$')
+           index_type = build_index_type (TREE_VALUE (size));
+       }
+      else if (minsize)
+       index_type = build_index_type (size_int (minsize - 1));
+
+      tree arat = NULL_TREE;
+      if (static_p || vla_p)
+       {
+         tree flag = static_p ? integer_one_node : NULL_TREE;
+         /* Hack: there's no language-independent way to encode
+            the "static" specifier or the "*" notation in an array type.
+            Add a "fake" attribute to have the pretty-printer add "static"
+            or "*".  The "[static N]" notation is only valid in the most
+            significant bound but [*] can be used for any bound.  Because
+            [*] is represented the same as [0] this hack only works for
+            the most significant bound like static and the others are
+            rendered as [0].  */
+         arat = build_tree_list (get_identifier ("array"), flag);
+       }
+
+      const int quals = TYPE_QUALS (type);
+      type = build_array_type (eltype, index_type);
+      type = build_type_attribute_qual_variant (type, arat, quals);
+    }
+
+  /* Format the type using the current pretty printer.  The generic tree
+     printer does a terrible job.  */
+  pretty_printer *pp = global_dc->printer->clone ();
+  pp_printf (pp, "%qT", type);
+  typstr = pp_formatted_text (pp);
+  delete pp;
+
+  return typstr;
+}
 
 #if CHECKING_P
 
@@ -2063,6 +2341,8 @@ struct excl_hash_traits: typed_noop_remove<excl_pair>
     x = value_type (NULL, NULL);
   }
 
+  static const bool empty_zero_p = false;
+
   static void mark_empty (value_type &x)
   {
     x = value_type ("", "");