c-parser.c (c_parser_has_attribute_expression): New function.
authorMartin Sebor <msebor@redhat.com>
Wed, 21 Nov 2018 02:50:02 +0000 (02:50 +0000)
committerMartin Sebor <msebor@gcc.gnu.org>
Wed, 21 Nov 2018 02:50:02 +0000 (19:50 -0700)
gcc/c/ChangeLog:

* c-parser.c (c_parser_has_attribute_expression): New function.
(c_parser_attribute): New function.
(c_parser_attributes): Move code into c_parser_attribute.
(c_parser_unary_expression): Handle RID_HAS_ATTRIBUTE_EXPRESSION.

gcc/c-family/ChangeLog:

* c-attribs.c (type_for_vector_size): New function.
(type_valid_for_vector_size): Same.
(handle_vector_size_attribute): Move code to the functions above
and call them.
(validate_attribute, has_attribute): New functions.
* c-common.h (has_attribute): Declare.
(rid): Add RID_HAS_ATTRIBUTE_EXPRESSION.
* c-common.c (c_common_resword): Same.

gcc/cp/ChangeLog:

* cp-tree.h (cp_check_const_attributes): Declare.
* decl2.c (cp_check_const_attributes): Declare extern.
* parser.c (cp_parser_has_attribute_expression): New function.
(cp_parser_unary_expression): Handle RID_HAS_ATTRIBUTE_EXPRESSION.
(cp_parser_gnu_attribute_list): Add argument.

gcc/ChangeLog:

* doc/extend.texi (Other Builtins): Add __builtin_has_attribute.

gcc/testsuite/ChangeLog:

* c-c++-common/builtin-has-attribute-2.c: New test.
* c-c++-common/builtin-has-attribute-3.c: New test.
* c-c++-common/builtin-has-attribute-4.c: New test.
* c-c++-common/builtin-has-attribute.c: New test.
* gcc.dg/builtin-has-attribute.c: New test.
* gcc/testsuite/gcc.target/i386/builtin-has-attribute.c: New test.

From-SVN: r266335

19 files changed:
gcc/ChangeLog
gcc/c-family/ChangeLog
gcc/c-family/c-attribs.c
gcc/c-family/c-common.c
gcc/c-family/c-common.h
gcc/c/ChangeLog
gcc/c/c-parser.c
gcc/cp/ChangeLog
gcc/cp/cp-tree.h
gcc/cp/decl2.c
gcc/cp/parser.c
gcc/doc/extend.texi
gcc/testsuite/ChangeLog
gcc/testsuite/c-c++-common/builtin-has-attribute-2.c [new file with mode: 0644]
gcc/testsuite/c-c++-common/builtin-has-attribute-3.c [new file with mode: 0644]
gcc/testsuite/c-c++-common/builtin-has-attribute-4.c [new file with mode: 0644]
gcc/testsuite/c-c++-common/builtin-has-attribute.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/builtin-has-attribute.c [new file with mode: 0644]
gcc/testsuite/gcc.target/i386/builtin-has-attribute.c [new file with mode: 0644]

index 3075648e439ec676d4aba88cb5ca3e018231a8e5..229e1b0e1670961b96511388d092864731e1d062 100644 (file)
@@ -1,3 +1,7 @@
+2018-11-20  Martin Sebor  <msebor@redhat.com>
+
+       * doc/extend.texi (Other Builtins): Add __builtin_has_attribute.
+
 2018-11-20  Jan Hubicka  <hubicka@ucw.cz>
 
        PR lto/84044
index db46542105101b8203ecd7a8486ed11d65d967d5..6d60cf02ed5aba57d33c2d3f5f9fc4965caa2fdf 100644 (file)
@@ -1,3 +1,14 @@
+2018-11-20  Martin Sebor  <msebor@redhat.com>
+
+       * c-attribs.c (type_for_vector_size): New function.
+       (type_valid_for_vector_size): Same.
+       (handle_vector_size_attribute): Move code to the functions above
+       and call them.
+       (validate_attribute, has_attribute): New functions.
+       * c-common.h (has_attribute): Declare.
+       (rid): Add RID_HAS_ATTRIBUTE_EXPRESSION.
+       * c-common.c (c_common_resword): Same.
+
 2018-11-16  Jason Merrill  <jason@redhat.com>
 
        * c-lex.c (c_common_has_attribute): Handle likely/unlikely.
index 88b24cd6cd49f14bfe24dc1f45c92ad4b702d48e..373381df68e63b27ce4ba8416e20a775381a0f2a 100644 (file)
@@ -4176,7 +4176,7 @@ has_attribute (location_t atloc, tree t, tree attr, tree (*convert)(tree))
              if (expr && DECL_P (expr))
                found_match = TREE_READONLY (expr);
            }
-         else if (!strcmp ("const", namestr))
+         else if (!strcmp ("pure", namestr))
            {
              if (expr && DECL_P (expr))
                found_match = DECL_PURE_P (expr);
index 4034b64bbe2a5f6410863274b291cf172dcf3c94..9d51815532d961fb9c472c319ae3fe329ebc85c3 100644 (file)
@@ -376,6 +376,7 @@ const struct c_common_resword c_common_reswords[] =
     RID_BUILTIN_CALL_WITH_STATIC_CHAIN, D_CONLY },
   { "__builtin_choose_expr", RID_CHOOSE_EXPR, D_CONLY },
   { "__builtin_complex", RID_BUILTIN_COMPLEX, D_CONLY },
+  { "__builtin_has_attribute", RID_BUILTIN_HAS_ATTRIBUTE, 0 },
   { "__builtin_launder", RID_BUILTIN_LAUNDER, D_CXXONLY },
   { "__builtin_shuffle", RID_BUILTIN_SHUFFLE, 0 },
   { "__builtin_tgmath", RID_BUILTIN_TGMATH, D_CONLY },
index 4aa614261142e4a6716cc7182fa731bc4bf586d8..4187343c0b3f7d6f7b3237ac6f610a3a143c2bcf 100644 (file)
@@ -103,6 +103,7 @@ enum rid
   RID_EXTENSION, RID_IMAGPART, RID_REALPART, RID_LABEL,      RID_CHOOSE_EXPR,
   RID_TYPES_COMPATIBLE_P,      RID_BUILTIN_COMPLEX,         RID_BUILTIN_SHUFFLE,
   RID_BUILTIN_TGMATH,
+  RID_BUILTIN_HAS_ATTRIBUTE,
   RID_DFLOAT32, RID_DFLOAT64, RID_DFLOAT128,
 
   /* TS 18661-3 keywords, in the same sequence as the TI_* values.  */
@@ -1355,6 +1356,7 @@ extern void maybe_suggest_missing_token_insertion (rich_location *richloc,
                                                   enum cpp_ttype token_type,
                                                   location_t prev_token_loc);
 extern tree braced_list_to_string (tree, tree);
+extern bool has_attribute (location_t, tree, tree, tree (*)(tree));
 
 #if CHECKING_P
 namespace selftest {
index 706839cd1cb3940dc473059ecce611f0ef0e4742..0b73df94db11939ea876d63d34bf82b7b3af74d4 100644 (file)
@@ -1,3 +1,10 @@
+2018-11-20  Martin Sebor  <msebor@redhat.com>
+
+       * c-parser.c (c_parser_has_attribute_expression): New function.
+       (c_parser_attribute): New function.
+       (c_parser_attributes): Move code into c_parser_attribute.
+       (c_parser_unary_expression): Handle RID_HAS_ATTRIBUTE_EXPRESSION.
+
 2018-11-15  Martin Sebor  <msebor@redhat.com>
 
        PR c/83656
index 5f69e9d52fd4e34feff73aabc79c369c51e9ee4b..afc40710e83a2aecd5a3323aa9d254ae843427f8 100644 (file)
@@ -1445,6 +1445,8 @@ static vec<tree, va_gc> *c_parser_expr_list (c_parser *, bool, bool,
                                             vec<tree, va_gc> **, location_t *,
                                             tree *, vec<location_t> *,
                                             unsigned int * = NULL);
+static struct c_expr c_parser_has_attribute_expression (c_parser *);
+
 static void c_parser_oacc_declare (c_parser *);
 static void c_parser_oacc_enter_exit_data (c_parser *, bool);
 static void c_parser_oacc_update (c_parser *);
@@ -4313,7 +4315,126 @@ c_parser_attribute_any_word (c_parser *parser)
    type), a reserved word storage class specifier, type specifier or
    type qualifier.  ??? This still leaves out most reserved keywords
    (following the old parser), shouldn't we include them, and why not
-   allow identifiers declared as types to start the arguments?  */
+   allow identifiers declared as types to start the arguments?
+   When EXPECT_COMMA is true, expect the attribute to be preceded
+   by a comma and fail if it isn't.
+   When EMPTY_OK is true, allow and consume any number of consecutive
+   commas with no attributes in between.  */
+
+static tree
+c_parser_attribute (c_parser *parser, tree attrs,
+                   bool expect_comma = false, bool empty_ok = true)
+{
+  bool comma_first = c_parser_next_token_is (parser, CPP_COMMA);
+  if (!comma_first
+      && !c_parser_next_token_is (parser, CPP_NAME)
+      && !c_parser_next_token_is (parser, CPP_KEYWORD))
+    return NULL_TREE;
+
+  while (c_parser_next_token_is (parser, CPP_COMMA))
+    {
+      c_parser_consume_token (parser);
+      if (!empty_ok)
+       return attrs;
+    }
+
+  tree attr_name = c_parser_attribute_any_word (parser);
+  if (attr_name == NULL_TREE)
+    return NULL_TREE;
+
+  attr_name = canonicalize_attr_name (attr_name);
+  c_parser_consume_token (parser);
+
+  tree attr;
+  if (c_parser_next_token_is_not (parser, CPP_OPEN_PAREN))
+    {
+      if (expect_comma && !comma_first)
+       {
+         /* A comma is missing between the last attribute on the chain
+            and this one.  */
+         c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
+                                    "expected %<)%>");
+         return error_mark_node;
+       }
+      attr = build_tree_list (attr_name, NULL_TREE);
+      /* Add this attribute to the list.  */
+      attrs = chainon (attrs, attr);
+      return attrs;
+    }
+  c_parser_consume_token (parser);
+
+  vec<tree, va_gc> *expr_list;
+  tree attr_args;
+  /* Parse the attribute contents.  If they start with an
+     identifier which is followed by a comma or close
+     parenthesis, then the arguments start with that
+     identifier; otherwise they are an expression list.
+     In objective-c the identifier may be a classname.  */
+  if (c_parser_next_token_is (parser, CPP_NAME)
+      && (c_parser_peek_token (parser)->id_kind == C_ID_ID
+         || (c_dialect_objc ()
+             && c_parser_peek_token (parser)->id_kind
+             == C_ID_CLASSNAME))
+      && ((c_parser_peek_2nd_token (parser)->type == CPP_COMMA)
+         || (c_parser_peek_2nd_token (parser)->type
+             == CPP_CLOSE_PAREN))
+      && (attribute_takes_identifier_p (attr_name)
+         || (c_dialect_objc ()
+             && c_parser_peek_token (parser)->id_kind
+             == C_ID_CLASSNAME)))
+    {
+      tree arg1 = c_parser_peek_token (parser)->value;
+      c_parser_consume_token (parser);
+      if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
+       attr_args = build_tree_list (NULL_TREE, arg1);
+      else
+       {
+         tree tree_list;
+         c_parser_consume_token (parser);
+         expr_list = c_parser_expr_list (parser, false, true,
+                                         NULL, NULL, NULL, NULL);
+         tree_list = build_tree_list_vec (expr_list);
+         attr_args = tree_cons (NULL_TREE, arg1, tree_list);
+         release_tree_vector (expr_list);
+       }
+    }
+  else
+    {
+      if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
+       attr_args = NULL_TREE;
+      else
+       {
+         expr_list = c_parser_expr_list (parser, false, true,
+                                         NULL, NULL, NULL, NULL);
+         attr_args = build_tree_list_vec (expr_list);
+         release_tree_vector (expr_list);
+       }
+    }
+
+  attr = build_tree_list (attr_name, attr_args);
+  if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
+    c_parser_consume_token (parser);
+  else
+    {
+      parser->lex_untranslated_string = false;
+      c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
+                                "expected %<)%>");
+      return error_mark_node;
+    }
+
+  if (expect_comma && !comma_first)
+    {
+      /* A comma is missing between the last attribute on the chain
+        and this one.  */
+      c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
+                                "expected %<)%>");
+      return error_mark_node;
+    }
+
+  /* Add this attribute to the list.  */
+  attrs = chainon (attrs, attr);
+  return attrs;
+}
 
 static tree
 c_parser_attributes (c_parser *parser)
@@ -4338,97 +4459,19 @@ c_parser_attributes (c_parser *parser)
          c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
          return attrs;
        }
-      /* Parse the attribute list.  */
-      while (c_parser_next_token_is (parser, CPP_COMMA)
-            || c_parser_next_token_is (parser, CPP_NAME)
-            || c_parser_next_token_is (parser, CPP_KEYWORD))
+      /* Parse the attribute list.  Require a comma between successive
+        (possibly empty) attributes.  */
+      for (bool expect_comma = false; ; expect_comma = true)
        {
-         tree attr, attr_name, attr_args;
-         vec<tree, va_gc> *expr_list;
-         if (c_parser_next_token_is (parser, CPP_COMMA))
-           {
-             c_parser_consume_token (parser);
-             continue;
-           }
-
-         attr_name = c_parser_attribute_any_word (parser);
-         if (attr_name == NULL)
+         /* Parse a single attribute.  */
+         tree attr = c_parser_attribute (parser, attrs, expect_comma);
+         if (attr == error_mark_node)
+           return attrs;
+         if (!attr)
            break;
-         attr_name = canonicalize_attr_name (attr_name);
-         c_parser_consume_token (parser);
-         if (c_parser_next_token_is_not (parser, CPP_OPEN_PAREN))
-           {
-             attr = build_tree_list (attr_name, NULL_TREE);
-             /* Add this attribute to the list.  */
-             attrs = chainon (attrs, attr);
-             /* If the next token isn't a comma, we're done.  */
-             if (!c_parser_next_token_is (parser, CPP_COMMA))
-               break;
-             continue;
-           }
-         c_parser_consume_token (parser);
-         /* Parse the attribute contents.  If they start with an
-            identifier which is followed by a comma or close
-            parenthesis, then the arguments start with that
-            identifier; otherwise they are an expression list.  
-            In objective-c the identifier may be a classname.  */
-         if (c_parser_next_token_is (parser, CPP_NAME)
-             && (c_parser_peek_token (parser)->id_kind == C_ID_ID
-                 || (c_dialect_objc ()
-                     && c_parser_peek_token (parser)->id_kind
-                        == C_ID_CLASSNAME))
-             && ((c_parser_peek_2nd_token (parser)->type == CPP_COMMA)
-                 || (c_parser_peek_2nd_token (parser)->type
-                     == CPP_CLOSE_PAREN))
-             && (attribute_takes_identifier_p (attr_name)
-                 || (c_dialect_objc ()
-                     && c_parser_peek_token (parser)->id_kind
-                        == C_ID_CLASSNAME)))
-           {
-             tree arg1 = c_parser_peek_token (parser)->value;
-             c_parser_consume_token (parser);
-             if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
-               attr_args = build_tree_list (NULL_TREE, arg1);
-             else
-               {
-                 tree tree_list;
-                 c_parser_consume_token (parser);
-                 expr_list = c_parser_expr_list (parser, false, true,
-                                                 NULL, NULL, NULL, NULL);
-                 tree_list = build_tree_list_vec (expr_list);
-                 attr_args = tree_cons (NULL_TREE, arg1, tree_list);
-                 release_tree_vector (expr_list);
-               }
-           }
-         else
-           {
-             if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
-               attr_args = NULL_TREE;
-             else
-               {
-                 expr_list = c_parser_expr_list (parser, false, true,
-                                                 NULL, NULL, NULL, NULL);
-                 attr_args = build_tree_list_vec (expr_list);
-                 release_tree_vector (expr_list);
-               }
-           }
+         attrs = attr;
+      }
 
-         attr = build_tree_list (attr_name, attr_args);
-         if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
-           c_parser_consume_token (parser);
-         else
-           {
-             parser->lex_untranslated_string = false;
-             c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
-                                        "expected %<)%>");
-             return attrs;
-           }
-         /* Add this attribute to the list.  */
-         attrs = chainon (attrs, attr);
-         /* If the next token isn't a comma, we're done.  */
-         if (!c_parser_next_token_is (parser, CPP_COMMA))
-           break;
-       }
       /* Look for the two `)' tokens.  */
       if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
        c_parser_consume_token (parser);
@@ -7263,6 +7306,8 @@ c_parser_unary_expression (c_parser *parser)
          return c_parser_sizeof_expression (parser);
        case RID_ALIGNOF:
          return c_parser_alignof_expression (parser);
+       case RID_BUILTIN_HAS_ATTRIBUTE:
+         return c_parser_has_attribute_expression (parser);
        case RID_EXTENSION:
          c_parser_consume_token (parser);
          ext = disable_extension_diagnostics ();
@@ -7462,6 +7507,123 @@ c_parser_alignof_expression (c_parser *parser)
     }
 }
 
+/* Parse the __builtin_has_attribute ([expr|type], attribute-spec)
+   expression.  */
+
+static struct c_expr
+c_parser_has_attribute_expression (c_parser *parser)
+{
+  gcc_assert (c_parser_next_token_is_keyword (parser,
+                                             RID_BUILTIN_HAS_ATTRIBUTE));
+  c_parser_consume_token (parser);
+
+  c_inhibit_evaluation_warnings++;
+
+  matching_parens parens;
+  if (!parens.require_open (parser))
+    {
+      c_inhibit_evaluation_warnings--;
+      in_typeof--;
+
+      struct c_expr result;
+      result.set_error ();
+      result.original_code = ERROR_MARK;
+      result.original_type = NULL;
+      return result;
+    }
+
+  /* Treat the type argument the same way as in typeof for the purposes
+     of warnings.  FIXME: Generalize this so the warning refers to
+     __builtin_has_attribute rather than typeof.  */
+  in_typeof++;
+
+  /* The first operand: one of DECL, EXPR, or TYPE.  */
+  tree oper = NULL_TREE;
+  if (c_parser_next_tokens_start_typename (parser, cla_prefer_id))
+    {
+      struct c_type_name *tname = c_parser_type_name (parser);
+      in_typeof--;
+      if (tname)
+       {
+         oper = groktypename (tname, NULL, NULL);
+         pop_maybe_used (variably_modified_type_p (oper, NULL_TREE));
+       }
+    }
+  else
+    {
+      struct c_expr cexpr = c_parser_expr_no_commas (parser, NULL);
+      c_inhibit_evaluation_warnings--;
+      in_typeof--;
+      if (cexpr.value != error_mark_node)
+       {
+         mark_exp_read (cexpr.value);
+         oper = cexpr.value;
+         tree etype = TREE_TYPE (oper);
+         bool was_vm = variably_modified_type_p (etype, NULL_TREE);
+         /* This is returned with the type so that when the type is
+            evaluated, this can be evaluated.  */
+         if (was_vm)
+           oper = c_fully_fold (oper, false, NULL);
+         pop_maybe_used (was_vm);
+       }
+    }
+
+  struct c_expr result;
+  result.original_code = ERROR_MARK;
+  result.original_type = NULL;
+
+  if (!c_parser_require (parser, CPP_COMMA, "expected %<,%>"))
+    {
+      /* Consume the closing parenthesis if that's the next token
+        in the likely case the built-in was invoked with fewer
+        than two arguments.  */
+      if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
+       c_parser_consume_token (parser);
+      c_inhibit_evaluation_warnings--;
+      result.set_error ();
+      return result;
+    }
+
+  parser->lex_untranslated_string = true;
+
+  location_t atloc = c_parser_peek_token (parser)->location;
+  /* Parse a single attribute.  Require no leading comma and do not
+     allow empty attributes.  */
+  tree attr = c_parser_attribute (parser, NULL_TREE, false, false);
+
+  parser->lex_untranslated_string = false;
+
+  if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
+    c_parser_consume_token (parser);
+  else
+    {
+      c_parser_error (parser, "expected identifier");
+      c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
+
+      result.set_error ();
+      return result;
+    }
+
+  if (!attr)
+    {
+      error_at (atloc, "expected identifier");
+      c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
+                                "expected %<)%>");
+      result.set_error ();
+      return result;
+    }
+
+  result.original_code = INTEGER_CST;
+  result.original_type = boolean_type_node;
+
+  if (has_attribute (atloc, oper, attr, default_conversion))
+    result.value = boolean_true_node;
+  else
+    result.value =  boolean_false_node;
+
+  return result;
+}
+
 /* Helper function to read arguments of builtins which are interfaces
    for the middle-end nodes like COMPLEX_EXPR, VEC_PERM_EXPR and
    others.  The name of the builtin is passed using BNAME parameter.
index a5ee86e781040d0bf080eb7ed4229208b808c313..a8e054442d6cc5fe1fe01207ac34765520087ef1 100644 (file)
@@ -1,3 +1,11 @@
+2018-11-20  Martin Sebor  <msebor@redhat.com>
+
+       * cp-tree.h (cp_check_const_attributes): Declare.
+       * decl2.c (cp_check_const_attributes): Declare extern.
+       * parser.c (cp_parser_has_attribute_expression): New function.
+       (cp_parser_unary_expression): Handle RID_HAS_ATTRIBUTE_EXPRESSION.
+       (cp_parser_gnu_attribute_list): Add argument.
+
 2018-11-20  Jakub Jelinek  <jakub@redhat.com>
 
        PR c++/88110
index edb94940098474198267b4fedf1d6a6db7ef8654..111a123bb34c50af51a92d3d82621307492c62b1 100644 (file)
@@ -6491,6 +6491,7 @@ extern int parm_index                           (tree);
 extern tree vtv_start_verification_constructor_init_function (void);
 extern tree vtv_finish_verification_constructor_init_function (tree);
 extern bool cp_omp_mappable_type               (tree);
+extern void cp_check_const_attributes (tree);
 
 /* in error.c */
 extern const char *type_as_string              (tree, int);
index 7686a908631a2fccb294fd8ac87673f7143a6a57..ffc0d0d6ec4b7d9fdc5990b6ce478218e66886ac 100644 (file)
@@ -1368,7 +1368,7 @@ cp_reconstruct_complex_type (tree type, tree bottom)
 /* Replaces any constexpr expression that may be into the attributes
    arguments with their reduced value.  */
 
-static void
+void
 cp_check_const_attributes (tree attributes)
 {
   if (attributes == error_mark_node)
index 292cce156769282f761ac2807e02ff59f300ae8c..0617f5636cdadd46bccd755755707f1f3e2eb679 100644 (file)
@@ -2048,6 +2048,8 @@ static cp_expr cp_parser_unary_expression
   (cp_parser *, cp_id_kind * = NULL, bool = false, bool = false, bool = false);
 static enum tree_code cp_parser_unary_operator
   (cp_token *);
+static tree cp_parser_has_attribute_expression
+  (cp_parser *);
 static tree cp_parser_new_expression
   (cp_parser *);
 static vec<tree, va_gc> *cp_parser_new_placement
@@ -2381,7 +2383,7 @@ static tree cp_parser_attributes_opt
 static tree cp_parser_gnu_attributes_opt
   (cp_parser *);
 static tree cp_parser_gnu_attribute_list
-  (cp_parser *);
+  (cp_parser *, bool = false);
 static tree cp_parser_std_attribute
   (cp_parser *, tree);
 static tree cp_parser_std_attribute_spec
@@ -8110,6 +8112,9 @@ cp_parser_unary_expression (cp_parser *parser, cp_id_kind * pidk,
            return ret_expr;
          }
 
+       case RID_BUILTIN_HAS_ATTRIBUTE:
+         return cp_parser_has_attribute_expression (parser);
+
        case RID_NEW:
          return cp_parser_new_expression (parser);
 
@@ -8407,6 +8412,121 @@ cp_parser_unary_operator (cp_token* token)
     }
 }
 
+/* Parse a __builtin_has_attribute([expr|type], attribute-spec) expression.
+   Returns a representation of the expression.  */
+
+static tree
+cp_parser_has_attribute_expression (cp_parser *parser)
+{
+  location_t start_loc = cp_lexer_peek_token (parser->lexer)->location;
+
+  /* Consume the __builtin_has_attribute token.  */
+  cp_lexer_consume_token (parser->lexer);
+
+  matching_parens parens;
+  if (!parens.require_open (parser))
+    return error_mark_node;
+
+  /* Types cannot be defined in a `sizeof' expression.  Save away the
+     old message.  */
+  const char *saved_message = parser->type_definition_forbidden_message;
+  /* And create the new one.  */
+  const int kwd = RID_BUILTIN_HAS_ATTRIBUTE;
+  char *tmp = concat ("types may not be defined in %<",
+                     IDENTIFIER_POINTER (ridpointers[kwd]),
+                     "%> expressions", NULL);
+  parser->type_definition_forbidden_message = tmp;
+
+  /* The restrictions on constant-expressions do not apply inside
+     sizeof expressions.  */
+  bool saved_integral_constant_expression_p
+    = parser->integral_constant_expression_p;
+  bool saved_non_integral_constant_expression_p
+    = parser->non_integral_constant_expression_p;
+  parser->integral_constant_expression_p = false;
+
+  /* Do not actually evaluate the expression.  */
+  ++cp_unevaluated_operand;
+  ++c_inhibit_evaluation_warnings;
+
+  tree oper = NULL_TREE;
+
+  /* We can't be sure yet whether we're looking at a type-id or an
+     expression.  */
+  cp_parser_parse_tentatively (parser);
+
+  bool saved_in_type_id_in_expr_p = parser->in_type_id_in_expr_p;
+  parser->in_type_id_in_expr_p = true;
+  /* Look for the type-id.  */
+  oper = cp_parser_type_id (parser);
+  parser->in_type_id_in_expr_p = saved_in_type_id_in_expr_p;
+
+  cp_parser_parse_definitely (parser);
+
+  /* If the type-id production did not work out, then we must be
+     looking at the unary-expression production.  */
+  if (!oper || oper == error_mark_node)
+    oper = cp_parser_unary_expression (parser);
+
+  /* Go back to evaluating expressions.  */
+  --cp_unevaluated_operand;
+  --c_inhibit_evaluation_warnings;
+
+  /* Free the message we created.  */
+  free (tmp);
+  /* And restore the old one.  */
+  parser->type_definition_forbidden_message = saved_message;
+  parser->integral_constant_expression_p
+    = saved_integral_constant_expression_p;
+  parser->non_integral_constant_expression_p
+    = saved_non_integral_constant_expression_p;
+
+  /* Consume the comma if it's there.  */
+  if (!cp_parser_require (parser, CPP_COMMA, RT_COMMA))
+    {
+      cp_parser_skip_to_closing_parenthesis (parser, false, false,
+                                            /*consume_paren=*/true);
+      return error_mark_node;
+    }
+
+  /* Parse the attribute specification.  */
+  bool ret = false;
+  location_t atloc = cp_lexer_peek_token (parser->lexer)->location;
+  if (tree attr = cp_parser_gnu_attribute_list (parser, /*exactly_one=*/true))
+    {
+      if (oper != error_mark_node)
+       {
+         /* Fold constant expressions used in attributes first.  */
+         cp_check_const_attributes (attr);
+
+         /* Finally, see if OPER has been declared with ATTR.  */
+         ret = has_attribute (atloc, oper, attr, default_conversion);
+       }
+
+      parens.require_close (parser);
+    }
+  else
+    {
+      error_at (atloc, "expected identifier");
+      cp_parser_skip_to_closing_parenthesis (parser, true, false, true);
+    }
+
+  /* Construct a location e.g. :
+     __builtin_has_attribute (oper, attr)
+     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+     with start == caret at the start of the built-in token,
+     and with the endpoint at the final closing paren.  */
+  location_t finish_loc
+    = cp_lexer_previous_token (parser->lexer)->location;
+  location_t compound_loc
+    = make_location (start_loc, start_loc, finish_loc);
+
+  cp_expr ret_expr (ret ? boolean_true_node : boolean_false_node);
+  ret_expr.set_location (compound_loc);
+  ret_expr = ret_expr.maybe_add_location_wrapper ();
+  return ret_expr;
+}
+
 /* Parse a new-expression.
 
    new-expression:
@@ -25376,7 +25496,7 @@ cp_parser_gnu_attributes_opt (cp_parser* parser)
    the arguments, if any.  */
 
 static tree
-cp_parser_gnu_attribute_list (cp_parser* parser)
+cp_parser_gnu_attribute_list (cp_parser* parser, bool exactly_one /* = false */)
 {
   tree attribute_list = NULL_TREE;
   bool save_translate_strings_p = parser->translate_strings_p;
@@ -25443,9 +25563,9 @@ cp_parser_gnu_attribute_list (cp_parser* parser)
 
          token = cp_lexer_peek_token (parser->lexer);
        }
-      /* Now, look for more attributes.  If the next token isn't a
-        `,', we're done.  */
-      if (token->type != CPP_COMMA)
+      /* Unless EXACTLY_ONE is set look for more attributes.
+        If the next token isn't a `,', we're done.  */
+      if (exactly_one || token->type != CPP_COMMA)
        break;
 
       /* Consume the comma and keep going.  */
index 0dff5e86ed190f71f6dbf766841c5ff91f56eab6..858b2d15440922fd4c6abf3521d71c2d6871421f 100644 (file)
@@ -11140,6 +11140,7 @@ is called and the @var{flag} argument passed to it.
 @findex __builtin_call_with_static_chain
 @findex __builtin_extend_pointer
 @findex __builtin_fpclassify
+@findex __builtin_has_attribute
 @findex __builtin_isfinite
 @findex __builtin_isnormal
 @findex __builtin_isgreater
@@ -11797,6 +11798,46 @@ check its compatibility with @var{size}.
 
 @end deftypefn
 
+@deftypefn {Built-in Function} bool __builtin_has_attribute (@var{type-or-expression}, @var{attribute})
+The @code{__builtin_has_attribute} function evaluates to an integer constant
+expression equal to @code{true} if the symbol or type referenced by
+the @var{type-or-expression} argument has been declared with
+the @var{attribute} referenced by the second argument.  Neither argument
+is evaluated.  The @var{type-or-expression} argument is subject to the same
+restrictions as the argument to @code{typeof} (@pxref{Typeof}).  The
+@var{attribute} argument is an attribute name optionally followed by
+a comma-separated list of arguments enclosed in parentheses.  Both forms
+of attribute names---with and without double leading and trailing
+underscores---are recognized.  See @xref{Attribute Syntax} for details.
+When no attribute arguments are specified for an attribute that expects
+one or more arguments the function returns @code{true} if
+@var{type-or-expression} has been declared with the attribute regardless
+of the attribute argument values.  Arguments provided for an attribute
+that expects some are validated and matched up to the provided number.
+The function returns @code{true} if all provided arguments match.  For
+example, the first call to the function below evaluates to @code{true}
+because @code{x} is declared with the @code{aligned} attribute but
+the second call evaluates to @code{false} because @code{x} is declared
+@code{aligned (8)} and not @code{aligned (4)}.
+
+@smallexample
+__attribute__ ((aligned (8))) int x;
+_Static_assert (__builtin_has_attribute (x, aligned), "aligned");
+_Static_assert (!__builtin_has_attribute (x, aligned (4)), "aligned (4)");
+@end smallexample
+
+Due to a limitation the @code{__builtin_has_attribute} function returns
+@code{false} for the @code{mode} attribute even if the type or variable
+referenced by the @var{type-or-expression} argument was declared with one.
+The function is also not supported with labels, and in C with enumerators.
+
+Note that unlike the @code{__has_attribute} preprocessor operator which
+is suitable for use in @code{#if} preprocessing directives
+@code{__builtin_has_attribute} is an intrinsic function that is not
+recognized in such contexts.
+
+@end deftypefn
+
 @deftypefn {Built-in Function} @var{type} __builtin_speculation_safe_value (@var{type} val, @var{type} failval)
 
 This built-in function can be used to help mitigate against unsafe
index d3ebbf0bcce3b901ad74fcb709d095c31901646f..43831fcfbb43f5ea4f450ac1dcda639b281ce517 100644 (file)
@@ -1,3 +1,12 @@
+2018-11-20  Martin Sebor  <msebor@redhat.com>
+
+       * c-c++-common/builtin-has-attribute-2.c: New test.
+       * c-c++-common/builtin-has-attribute-3.c: New test.
+       * c-c++-common/builtin-has-attribute-4.c: New test.
+       * c-c++-common/builtin-has-attribute.c: New test.
+       * gcc.dg/builtin-has-attribute.c: New test.
+       * gcc/testsuite/gcc.target/i386/builtin-has-attribute.c: New test.
+
 2018-11-20  Jan Hubicka  <hubicka@ucw.cz>
 
        PR lto/84044
diff --git a/gcc/testsuite/c-c++-common/builtin-has-attribute-2.c b/gcc/testsuite/c-c++-common/builtin-has-attribute-2.c
new file mode 100644 (file)
index 0000000..0f692ff
--- /dev/null
@@ -0,0 +1,206 @@
+/* Verify __builtin_has_attribute return value for types.
+   { dg-do compile }
+   { dg-options "-Wall -ftrack-macro-expansion=0" }
+   { dg-options "-Wall -Wno-narrowing -Wno-unused-local-typedefs -ftrack-macro-expansion=0" { target c++ } }  */
+
+#define ATTR(...) __attribute__ ((__VA_ARGS__))
+
+#define A(expect, sym, attr)                                           \
+  typedef int Assert [1 - 2 * !(__builtin_has_attribute (sym, attr) == expect)]
+
+struct ATTR (packed) Packed { char c; int i; };
+
+void fvoid (void);
+struct Packed fpacked (void);
+
+union OrdinaryUnion { void *p; int i; };
+union ATTR (transparent_union) TransparentUnion { void *p; int i; };
+
+/* Exercise __builtin_has_attribute with the first argument that
+   is a type.  */
+
+void test_type (int n)
+{
+  /* Verify both forms of the attribute spelling.  Unlike the attribute
+     keyword that can be spelled three ways (with either leading or
+     trailing underscores, or with both), attribute names can only be
+     spelled two ways.  */
+  A (0, int, aligned);
+  A (0, int, __aligned__);
+
+  A (0, int, aligned (1));
+  A (0, int, aligned (2));
+  A (0, int[1], aligned);
+  A (0, int[1], aligned (2));
+  A (0, int[n], aligned);
+  A (0, int[n], aligned (4));
+
+  /* Again, verify both forms of the attribute spelling.  */
+  A (1, ATTR (aligned) char, aligned);
+  A (1, ATTR (aligned (2)) short, aligned);
+  A (1, ATTR (aligned (4)) int, __aligned__);
+
+  A (0, int ATTR (aligned (4)), aligned (2));
+  A (0, int ATTR (aligned (2)), aligned (4));
+  /* GCC retains both attributes in the */
+  A (0, int ATTR (aligned (2), aligned (4)), aligned (2));
+  A (1, int ATTR (aligned (2), aligned (4)), aligned (4));
+  /* The following fails due to bug 87524.
+     A (1, int ATTR (aligned (4), aligned (2))), aligned (4)); */
+  A (0, int ATTR (aligned (4), aligned (2)), aligned (8));
+
+  A (1, int ATTR (aligned (8)), aligned (1 + 7));
+
+  enum { eight = 8 };
+  A (1, int ATTR (aligned (8)), aligned (eight));
+  A (1, int ATTR (aligned (eight)), aligned (1 + 7));
+
+  struct NotPacked { char c; int i; };
+  A (0, struct NotPacked, packed);
+  A (1, struct Packed, packed);
+
+  /* Exercise types returned from a function.  */
+  A (0, fvoid (), packed);
+  A (1, fpacked (), packed);
+
+  struct ATTR (aligned (2), packed) Aligned2Packed { char c; int i; };
+  A (1, struct Aligned2Packed, aligned);
+  A (1, struct Aligned2Packed, aligned (2));
+  A (0, struct Aligned2Packed, aligned (4));
+  A (1, struct Aligned2Packed, packed);
+
+  A (0, int, may_alias);
+  A (1, ATTR (may_alias) int, may_alias);
+
+  A (0, char, warn_if_not_aligned (1));
+  A (0, char, warn_if_not_aligned (2));
+
+  A (1, ATTR (warn_if_not_aligned (2)) char, warn_if_not_aligned);
+  A (0, ATTR (warn_if_not_aligned (2)) char, warn_if_not_aligned (1));
+  A (1, ATTR (warn_if_not_aligned (2)) char, warn_if_not_aligned (2));
+  A (0, ATTR (warn_if_not_aligned (2)) char, warn_if_not_aligned (4));
+
+  A (0, union OrdinaryUnion, transparent_union);
+
+  A (1, union TransparentUnion, transparent_union);
+  A (1, const union TransparentUnion, transparent_union);
+}
+
+/* Exercise __builtin_has_attribute with the first argument that
+   is a typedef.  */
+
+void test_typedef (int n)
+{
+  typedef char A1[1];
+  A (0, A1, aligned);
+  A (0, A1, aligned (1));
+  A (0, A1, aligned (2));
+
+  typedef char An[n];
+  A (0, An, aligned);
+  A (0, An, aligned (1));
+  A (0, An, aligned (2));
+
+  typedef ATTR (aligned (8)) short AI8;
+  A (1, AI8, aligned);
+  A (0, AI8, aligned (4));
+  A (1, AI8, aligned (8));
+  A (0, AI8, aligned (16));
+
+  A (1, const AI8, aligned);
+  A (1, const volatile AI8, aligned);
+
+  typedef ATTR (aligned (2), aligned (8), aligned (16)) int AI16;
+  A (1, AI16, aligned);
+  A (0, AI16, aligned (1));
+  A (0, AI16, aligned (2));
+  A (0, AI16, aligned (4));
+  A (0, AI16, aligned (8));
+  A (1, AI16, aligned (16));
+  A (0, AI16, aligned (32));
+
+  typedef const AI16 CAI16;
+  A (1, CAI16, aligned);
+  A (0, CAI16, aligned (1));
+  A (1, CAI16, aligned (16));
+
+  typedef int I;
+  A (0, I, may_alias);
+  A (0, AI8, may_alias);
+
+  typedef ATTR (may_alias) int MAI;
+  A (1, MAI, may_alias);
+
+  typedef ATTR (aligned (4), may_alias) char A4MAC;
+  A (0, A4MAC, aligned (0));
+  A (0, A4MAC, aligned (1));
+  A (0, A4MAC, aligned (2));
+  A (1, A4MAC, aligned (4));
+  A (0, A4MAC, aligned (8));
+  A (1, A4MAC, may_alias);
+
+  typedef ATTR (may_alias, aligned (8)) char A8MAC;
+  A (1, A8MAC, aligned);
+  A (0, A8MAC, aligned (0));
+  A (0, A8MAC, aligned (1));
+  A (0, A8MAC, aligned (2));
+  A (0, A8MAC, aligned (4));
+  A (1, A8MAC, aligned (8));
+  A (0, A8MAC, aligned (16));
+  A (1, A8MAC, may_alias);
+
+  typedef ATTR (may_alias) const AI8 CMAI8;
+  A (1, CMAI8, aligned);
+  A (1, CMAI8, may_alias);
+  A (0, CMAI8, aligned (4));
+  A (1, CMAI8, aligned (8));
+
+  typedef void Fnull (void*, void*, void*);
+  A (0, Fnull, nonnull);
+  A (0, Fnull, nonnull (1));
+  A (0, Fnull, nonnull (2));
+  A (0, Fnull, nonnull (3));
+
+  typedef ATTR (nonnull) Fnull Fnonnull;
+  A (1, Fnonnull, nonnull);
+  A (1, Fnonnull, nonnull (1));
+  A (1, Fnonnull, nonnull (2));
+  A (1, Fnonnull, nonnull (3));
+
+  typedef ATTR (nonnull (2)) void Fnonnull_2 (void*, void*, void*);
+  A (0, Fnonnull_2, nonnull);
+  A (0, Fnonnull_2, nonnull (1));
+  A (1, Fnonnull_2, nonnull (2));
+  A (0, Fnonnull_2, nonnull (3));
+
+  typedef ATTR (nonnull (1), nonnull (2), nonnull (3))
+    void Fnonnull_1_2_3 (void*, void*, void*);
+
+  /* The following fails because  the built-in doesn't recognize that
+     a single nonnull with no arguments is the same as one nonnull for
+     each function parameter.  Disable the testing for now.
+     A (1, Fnonnull_1_2_3, nonnull);
+  */
+  A (1, Fnonnull_1_2_3, nonnull (1));
+  A (1, Fnonnull_1_2_3, nonnull (2));
+  A (1, Fnonnull_1_2_3, nonnull (3));
+
+  typedef void Freturns (void);
+  A (0, Fnull, noreturn);
+  A (0, Freturns, noreturn);
+
+  typedef ATTR (warn_if_not_aligned (8)) char CWA8;
+  A (0, CWA8, warn_if_not_aligned (2));
+  A (0, CWA8, warn_if_not_aligned (4));
+  A (1, CWA8, warn_if_not_aligned (8));
+  A (0, CWA8, warn_if_not_aligned (16));
+
+  typedef union OrdinaryUnion OrdUnion;
+  A (0, OrdUnion, transparent_union);
+
+  /* The attribute is ignored on typedefs but GCC fails to diagnose
+     it (see bug ).  */
+  typedef union ATTR (transparent_union)
+    OrdinaryUnion TransUnion;   /* { dg-warning "\\\[-Wattributes" "pr87578" { xfail { ! { c++ } } } } */
+  A (0, TransUnion, transparent_union);
+}
diff --git a/gcc/testsuite/c-c++-common/builtin-has-attribute-3.c b/gcc/testsuite/c-c++-common/builtin-has-attribute-3.c
new file mode 100644 (file)
index 0000000..237dc72
--- /dev/null
@@ -0,0 +1,314 @@
+/* Verify __builtin_has_attribute return value for functions.
+   { dg-do compile }
+   { dg-options "-Wall -ftrack-macro-expansion=0" }
+   { dg-options "-Wall -Wno-narrowing -Wno-unused-local-typedefs -ftrack-macro-expansion=0" { target c++ } }  */
+
+#define ATTR(...) __attribute__ ((__VA_ARGS__))
+
+void fnone (void);
+
+ATTR (aligned) void faligned (void);
+ATTR (aligned (1)) void faligned_1 (void);
+ATTR (aligned (2)) void faligned_2 (void);
+ATTR (aligned (4)) void faligned_4 (void);
+ATTR (aligned (8)) void faligned_8 (void);
+
+ATTR (alloc_size (1)) void* falloc_size_1 (int, int);
+ATTR (alloc_size (2)) void* falloc_size_2 (int, int);
+ATTR (alloc_size (2, 4)) void* falloc_size_2_4 (int, int, int, int);
+
+ATTR (alloc_align (1)) void* falloc_align_1 (int, int);
+ATTR (alloc_align (2)) void* falloc_align_2 (int, int);
+ATTR (alloc_align (1), alloc_size (2)) void* falloc_align_1_size_2 (int, int);
+ATTR (alloc_align (2), alloc_size (1)) void* falloc_align_2_size_1 (int, int);
+
+#if __cplusplus
+extern "C"
+#endif
+ATTR (noreturn) void fnoreturn (void) { __builtin_abort (); }
+
+ATTR (alias ("fnoreturn")) void falias (void);
+
+#define A(expect, sym, attr)                                           \
+  typedef int Assert [1 - 2 * !(__builtin_has_attribute (sym, attr) == expect)]
+
+void test_aligned (void)
+{
+  A (0, fnone, aligned);
+  A (0, fnone, aligned (0));
+  A (0, fnone, aligned (1));
+  A (0, fnone, aligned (2));
+  A (0, fnone, aligned (4));
+  A (0, fnone, aligned (8));
+  A (0, fnone, aligned (16));
+
+  A (1, faligned, aligned);
+  A (0, faligned, aligned (0));
+  A (0, faligned, aligned (1));
+  A (0, faligned, aligned (2));
+
+  A (1, faligned_1, aligned);
+  A (0, faligned_1, aligned (0));
+  A (1, faligned_1, aligned (1));
+  A (0, faligned_1, aligned (2));
+  A (0, faligned_1, aligned (4));
+
+  A (1, faligned_2, aligned);
+  A (0, faligned_2, aligned (0));
+  A (0, faligned_2, aligned (1));
+  A (1, faligned_2, aligned (2));
+  A (0, faligned_2, aligned (4));
+}
+
+
+void test_alloc_align (void)
+{
+  A (0, fnone, alloc_align);
+  A (0, falloc_size_1, alloc_align);
+  A (1, falloc_align_1, alloc_align);
+  A (1, falloc_align_2, alloc_align);
+
+  A (0, fnone, alloc_align (1));        /* { dg-warning "\\\[-Wattributes" } */
+  A (0, falloc_size_1, alloc_align (1));
+  A (1, falloc_align_1, alloc_align (1));
+  A (0, falloc_align_2, alloc_align (1));
+  A (1, falloc_align_2, alloc_align (2));
+}
+
+
+void test_alloc_size_malloc (void)
+{
+  A (0, fnone, alloc_size);
+  A (0, fnone, alloc_size (1));         /* { dg-warning "\\\[-Wattributes" } */
+  A (0, fnone, alloc_size (2));         /* { dg-warning "\\\[-Wattributes" } */
+  A (0, falloc_align_1, alloc_size (1));
+  A (0, falloc_align_2, alloc_size (1));
+  A (1, falloc_size_1, alloc_size (1));
+  A (0, falloc_size_1, alloc_size (2));
+  A (0, falloc_size_2, alloc_size (1));
+  A (1, falloc_size_2, alloc_size (2));
+
+  A (1, falloc_size_2_4, alloc_size);
+  /* It would probably make more sense to have the built-in return
+     true only when both alloc_size arguments match, not just one
+     or the other.  */
+  A (0, falloc_size_2_4, alloc_size (1));
+  A (1, falloc_size_2_4, alloc_size (2));
+  A (0, falloc_size_2_4, alloc_size (3));
+  A (1, falloc_size_2_4, alloc_size (4));
+  A (1, falloc_size_2_4, alloc_size (2, 4));
+
+  extern ATTR (alloc_size (3))
+    void* fmalloc_size_3 (int, int, int);
+
+  A (1, fmalloc_size_3, alloc_size);
+  A (0, fmalloc_size_3, alloc_size (1));
+  A (0, fmalloc_size_3, alloc_size (2));
+  A (1, fmalloc_size_3, alloc_size (3));
+  A (0, fmalloc_size_3, malloc);
+
+  extern ATTR (malloc)
+    void* fmalloc_size_3 (int, int, int);
+
+  A (1, fmalloc_size_3, alloc_size (3));
+  A (1, fmalloc_size_3, malloc);
+}
+
+
+void test_alias (void)
+{
+  A (0, fnoreturn, alias);
+  A (1, falias, alias);
+  A (1, falias, alias ("fnoreturn"));
+  A (0, falias, alias ("falias"));
+  A (0, falias, alias ("fnone"));
+}
+
+
+void test_cold_hot (void)
+{
+  extern ATTR (cold) void fcold (void);
+  extern ATTR (hot) void fhot (void);
+
+  A (0, fnone, cold);
+  A (0, fnone, hot);
+
+  A (1, fcold, cold);
+  A (0, fcold, hot);
+
+  A (0, fhot, cold);
+  A (1, fhot, hot);
+}
+
+
+void test_const_leaf_pure (void)
+{
+  extern ATTR (const) int fconst (void);
+  extern ATTR (leaf) int fleaf (void);
+  extern ATTR (pure) int fpure (void);
+
+  A (0, fnone, const);
+  A (0, fnone, leaf);
+  A (0, fnone, pure);
+
+  A (1, fconst, const);
+  A (0, fconst, leaf);
+  A (0, fconst, pure);
+
+  A (0, fleaf, const);
+  A (1, fleaf, leaf);
+  A (0, fleaf, pure);
+
+  A (0, fpure, const);
+  A (0, fpure, leaf);
+  A (1, fpure, pure);
+
+  extern ATTR (const, leaf) int fconst_leaf (void);
+
+  A (1, fconst_leaf, const);
+  A (1, fconst_leaf, leaf);
+
+  extern ATTR (leaf, const) int fleaf_const (void);
+
+  A (1, fleaf_const, const);
+  A (1, fleaf_const, leaf);
+}
+
+
+void test_ctor_dtor (void)
+{
+  extern ATTR (constructor) void fctor (void);
+  extern ATTR (destructor) void fdtor (void);
+  extern ATTR (constructor, destructor) void fctor_dtor (void);
+
+  A (0, fnone, constructor);
+  A (0, fnone, destructor);
+
+  A (1, fctor, constructor);
+  A (1, fdtor, destructor);
+
+  extern ATTR (constructor) void fctor_dtor (void);
+  extern ATTR (destructor) void fctor_dtor (void);
+  extern ATTR (constructor, destructor) void fctor_dtor (void);
+
+  A (1, fctor_dtor, constructor);
+  A (1, fctor_dtor, destructor);
+
+  extern ATTR (constructor (123)) void fctor_123 (void);
+  A (1, fctor_123, constructor);
+  A (0, fctor_123, destructor);
+  A (1, fctor_123, constructor (123));
+  A (0, fctor_123, constructor (124));
+
+  extern ATTR (destructor (234)) void fctor_123 (void);
+  A (1, fctor_123, constructor (123));
+  A (1, fctor_123, destructor);
+  A (1, fctor_123, destructor (234));
+  A (0, fctor_123, destructor (235));
+}
+
+
+void test_externally_visible (void)
+{
+  extern void fexternally_visible (void);
+
+  A (0, fexternally_visible, externally_visible);
+
+  extern ATTR (externally_visible) void fexternally_visible (void);
+
+  A (1, fexternally_visible, externally_visible);
+}
+
+
+void test_flatten (void)
+{
+  extern void fflatten (void);
+
+  A (0, fflatten, flatten);
+
+  extern ATTR (flatten) void fflatten (void);
+
+  A (1, fflatten, flatten);
+
+  extern void fflatten (void);
+
+  A (1, fflatten, flatten);
+}
+
+
+ATTR (format (printf, 2, 4)) void
+fformat_printf_2_3 (int, const char*, int, ...);
+
+void test_format (void)
+{
+  A (0, fnone, format);
+  A (0, fnone, format (printf));
+  A (0, fnone, format (printf, 2));
+}
+
+
+inline void finline (void) { }
+inline ATTR (always_inline) void falways_inline (void) { }
+inline ATTR (always_inline, gnu_inline) void falways_gnu_inline (void) { }
+ATTR (noinline) void fnoinline () { }
+
+void test_inline (void)
+{
+  A (0, fnone, always_inline);
+  A (0, fnone, gnu_inline);
+  A (0, fnone, noinline);
+
+  A (0, finline, always_inline);
+  A (0, finline, gnu_inline);
+  A (0, finline, noinline);
+
+  A (1, falways_inline, always_inline);
+  A (0, falways_inline, gnu_inline);
+  A (0, falways_inline, noinline);
+
+  A (1, falways_gnu_inline, always_inline);
+  A (1, falways_gnu_inline, gnu_inline);
+  A (0, falways_gnu_inline, noinline);
+
+  A (0, fnoinline, always_inline);
+  A (0, fnoinline, gnu_inline);
+  A (1, fnoinline, noinline);
+}
+
+
+ATTR (no_instrument_function) void fno_instrument (void);
+
+ATTR (visibility ("default")) void fdefault (void);
+ATTR (visibility ("hidden")) void fhidden (void);
+ATTR (visibility ("internal")) void finternal (void);
+ATTR (visibility ("protected")) void fprotected (void);
+
+void test_visibility (void)
+{
+  A (0, fnone, visibility ("default"));
+  A (0, fnone, visibility ("hidden"));
+  A (0, fnone, visibility ("internal"));
+  A (0, fnone, visibility ("protected"));
+
+  A (1, fdefault, visibility ("default"));
+  A (0, fdefault, visibility ("hidden"));
+  A (0, fdefault, visibility ("internal"));
+  A (0, fdefault, visibility ("protected"));
+
+  A (0, fhidden, visibility ("default"));
+  A (1, fhidden, visibility ("hidden"));
+  A (0, fhidden, visibility ("internal"));
+  A (0, fhidden, visibility ("protected"));
+
+  A (0, finternal, visibility ("default"));
+  A (0, finternal, visibility ("hidden"));
+  A (1, finternal, visibility ("internal"));
+  A (0, finternal, visibility ("protected"));
+
+  A (0, fprotected, visibility ("default"));
+  A (0, fprotected, visibility ("hidden"));
+  A (0, fprotected, visibility ("internal"));
+  A (1, fprotected, visibility ("protected"));
+}
+
+/* { dg-prune-output "specifies less restrictive attribute" } */
diff --git a/gcc/testsuite/c-c++-common/builtin-has-attribute-4.c b/gcc/testsuite/c-c++-common/builtin-has-attribute-4.c
new file mode 100644 (file)
index 0000000..14bdd3f
--- /dev/null
@@ -0,0 +1,285 @@
+/* Verify __builtin_has_attribute return value for variables.
+   { dg-do compile }
+   { dg-options "-Wall -ftrack-macro-expansion=0" }
+   { dg-options "-Wall -Wno-narrowing -Wno-unused -ftrack-macro-expansion=0" { target c++ } }  */
+
+#define ATTR(...) __attribute__ ((__VA_ARGS__))
+
+#define A(expect, sym, attr)                                           \
+  typedef int Assert [1 - 2 * !(__builtin_has_attribute (sym, attr) == expect)]
+
+int vnone;
+
+ATTR (aligned) char valigned;
+ATTR (aligned (1)) char valigned_1;
+ATTR (aligned (2)) char valigned_2;
+ATTR (aligned (4)) char valigned_4;
+ATTR (aligned (8)) char valigned_8;
+
+void test_aligned (void)
+{
+  A (0, vnone, aligned);
+  A (0, vnone, aligned (0));
+  A (0, vnone, aligned (1));
+  A (0, vnone, aligned (2));
+  A (0, vnone, aligned (4));
+  A (0, vnone, aligned (8));
+  A (0, vnone, aligned (16));
+
+  A (1, valigned, aligned);
+  A (0, valigned, aligned (0));
+  A (0, valigned, aligned (1));
+  A (0, valigned, aligned (2));
+
+  A (1, valigned_1, aligned);
+  A (0, valigned_1, aligned (0));
+  A (1, valigned_1, aligned (1));
+  A (0, valigned_1, aligned (2));
+  A (0, valigned_1, aligned (4));
+
+  A (1, valigned_2, aligned);
+  A (0, valigned_2, aligned (0));
+  A (0, valigned_2, aligned (1));
+  A (1, valigned_2, aligned (2));
+  A (0, valigned_2, aligned (4));
+}
+
+
+int vtarget;
+extern ATTR (alias ("vtarget")) int valias;
+
+void test_alias (void)
+{
+  A (0, vnone, alias);
+  A (1, valias, alias);
+  A (1, valias, alias ("vtarget"));
+  A (0, valias, alias ("vnone"));
+}
+
+
+void test_cleanup (void)
+{
+  extern void fpv (void*);
+  extern void fcleanup (void*);
+
+  int var;
+  ATTR (cleanup (fcleanup)) int var_cleanup;
+  A (0, var, cleanup);
+  A (1, var_cleanup, cleanup);
+  A (1, var_cleanup, cleanup (fcleanup));
+  A (0, var_cleanup, cleanup (fpv));
+}
+
+
+ATTR (common) int vcommon;
+ATTR (nocommon) int vnocommon;
+
+void test_common (void)
+{
+  A (0, vnone, common);
+  A (0, vnone, nocommon);
+
+  A (1, vcommon, common);
+  A (0, vcommon, nocommon);
+
+  A (0, vnocommon, common);
+  A (1, vnocommon, nocommon);
+}
+
+
+void test_externally_visible (void)
+{
+  extern int vexternally_visible;
+
+  A (0, vexternally_visible, externally_visible);
+
+  extern ATTR (externally_visible) int vexternally_visible;
+
+  A (1, vexternally_visible, externally_visible);
+}
+
+
+int test_mode (void)
+{
+  ATTR (mode (byte)) int i8;
+  return __builtin_has_attribute (i8, mode);   /* { dg-warning ".mode. attribute not supported in .__builtin_has_attribute." } */
+}
+
+
+void test_nonstring (void)
+{
+  char arr[1];
+  char* ptr = arr;
+
+  ATTR (nonstring) char arr_nonstring[1];
+  ATTR (nonstring) char *ptr_nonstring =  arr_nonstring;
+
+  A (0, arr, nonstring);
+  A (0, ptr, nonstring);
+
+  A (1, arr_nonstring, nonstring);
+  A (1, ptr_nonstring, nonstring);
+}
+
+struct PackedMember
+{
+  char c;
+  short s;
+  int i;
+  ATTR (packed) int a[2];
+} gpak[2];
+
+void test_packed (struct PackedMember *p)
+{
+  int vunpacked;
+  ATTR (packed) int vpacked;   /* { dg-warning ".packed. attribute ignored" } */
+
+  A (0, vunpacked, packed);
+  A (0, vpacked, packed);
+
+  int arr_unpacked[2];
+  ATTR (packed) int arr_packed[2];   /* { dg-warning ".packed. attribute ignored" } */
+
+  A (0, arr_unpacked, packed);
+  A (0, arr_packed, packed);
+  A (0, arr_unpacked[0], packed);
+  A (0, arr_packed[0], packed);
+
+  A (0, gpak, packed);
+  A (0, gpak[0], packed);
+  A (0, *gpak, packed);
+  A (0, gpak[0].c, packed);
+  A (0, gpak[1].s, packed);
+  A (1, gpak->a, packed);
+  A (1, (*gpak).a[0], packed);
+
+  /* The following fails because in C it's represented as
+       INDIRECT_REF (POINTER_PLUS (NOP_EXPR (ADDR_EXPR (gpak)), ...))
+     with no reference to the member.  Avoid testing it.
+  A (1, *gpak[9].a, packed);  */
+
+  A (0, p->c, packed);
+  A (0, p->s, packed);
+  A (1, p->a, packed);
+  A (1, p->a[0], packed);
+  /* Similar to the comment above.
+   A (1, *p->a, packed);  */
+}
+
+
+ATTR (section ("sectA")) int var_sectA;
+ATTR (section ("sectB")) int var_sectB;
+
+void test_section (void)
+{
+  int var = 0;
+  A (0, var, section);
+  A (0, var, section ("sectA"));
+
+  A (1, var_sectA, section);
+  A (1, var_sectA, section ("sectA"));
+  A (0, var_sectA, section ("sectB"));
+
+  A (1, var_sectB, section);
+  A (0, var_sectB, section ("sectA"));
+  A (1, var_sectB, section ("sectB"));
+}
+
+
+void test_vector_size (void)
+{
+  char c;
+  extern int arrx[];
+  extern int arr1[1];
+
+  A (0, c, vector_size);
+  A (0, c, vector_size (1));
+  A (0, arrx, vector_size);
+  A (0, arrx, vector_size (4));
+  A (0, arr1, vector_size);
+  A (0, arr1, vector_size (8));
+
+  ATTR (vector_size (4)) char cv4;
+  ATTR (vector_size (16)) int iv16;
+
+  A (1, cv4, vector_size);
+  A (0, cv4, vector_size (1));
+  A (0, cv4, vector_size (2));
+  A (1, cv4, vector_size (4));
+  A (0, cv4, vector_size (8));
+
+  A (1, iv16, vector_size);
+  A (0, iv16, vector_size (1));
+  A (0, iv16, vector_size (8));
+  A (1, iv16, vector_size (16));
+  A (0, iv16, vector_size (32));
+
+  ATTR (vector_size (8)) float afv8[4];
+  A (1, afv8, vector_size);
+  A (0, afv8, vector_size (1));
+  A (0, afv8, vector_size (2));
+  A (0, afv8, vector_size (4));
+  A (1, afv8, vector_size (8));
+  A (0, afv8, vector_size (16));
+}
+
+
+ATTR (visibility ("default")) int vdefault;
+ATTR (visibility ("hidden")) int vhidden;
+ATTR (visibility ("internal")) int vinternal;
+ATTR (visibility ("protected")) int vprotected;
+
+void test_visibility (void)
+{
+  A (0, vnone, visibility ("default"));
+  A (0, vnone, visibility ("hidden"));
+  A (0, vnone, visibility ("internal"));
+  A (0, vnone, visibility ("protected"));
+
+  A (1, vdefault, visibility ("default"));
+  A (0, vdefault, visibility ("hidden"));
+  A (0, vdefault, visibility ("internal"));
+  A (0, vdefault, visibility ("protected"));
+
+  A (0, vhidden, visibility ("default"));
+  A (1, vhidden, visibility ("hidden"));
+  A (0, vhidden, visibility ("internal"));
+  A (0, vhidden, visibility ("protected"));
+
+  A (0, vinternal, visibility ("default"));
+  A (0, vinternal, visibility ("hidden"));
+  A (1, vinternal, visibility ("internal"));
+  A (0, vinternal, visibility ("protected"));
+
+  A (0, vprotected, visibility ("default"));
+  A (0, vprotected, visibility ("hidden"));
+  A (0, vprotected, visibility ("internal"));
+  A (1, vprotected, visibility ("protected"));
+}
+
+
+int var_init_strong = 123;
+int var_uninit_strong;
+static int var_extern_strong;
+static int var_static_strong;
+
+ATTR (weak) int var_init_weak = 234;
+ATTR (weak) int var_uninit_weak;
+
+void test_weak (void)
+{
+  int var_local = 0;
+  static int var_static_local = 0;
+
+  A (0, var_init_strong, weak);
+  A (0, var_uninit_strong, weak);
+  A (0, var_extern_strong, weak);
+  A (0, var_static_strong, weak);
+  A (0, var_local, weak);
+  A (0, var_static_local, weak);
+
+  A (1, var_init_weak, weak);
+  A (1, var_uninit_weak, weak);
+}
+
+/* { dg-prune-output "specifies less restrictive attribute" } */
diff --git a/gcc/testsuite/c-c++-common/builtin-has-attribute.c b/gcc/testsuite/c-c++-common/builtin-has-attribute.c
new file mode 100644 (file)
index 0000000..67c792f
--- /dev/null
@@ -0,0 +1,60 @@
+/* Verify __builtin_has_attribute error handling.
+   { dg-do compile }
+   { dg-options "-Wall -ftrack-macro-expansion=0" }  */
+
+#define ATTR(list) __attribute__ (list)
+
+void fnone (void);
+
+ATTR ((aligned)) void faligned (void);
+ATTR ((aligned (8))) void faligned_8 (void);
+
+#define has_attr(x, attr)   __builtin_has_attribute (x, attr)
+
+#define A(expect, sym, attr)                                           \
+  typedef int Assert [1 - 2 * !(has_attr (sym, attr) == expect)]
+
+
+int b;
+
+/* Exercise syntactically invalid arguments.  */
+
+void test_bad_arguments (void)
+{
+  b = __builtin_has_attribute ();            /* { dg-error "expected \(primary-\)?expression|expected .,." } */
+  b = __builtin_has_attribute (1);           /* { dg-error "expected .,." } */
+  b = __builtin_has_attribute (void);        /* { dg-error "expected .,." } */
+  b = __builtin_has_attribute (foo);         /* { dg-error ".foo. \(undeclared|was not declared\)" } */
+  /* { dg-error "expected .,." "missing comma" { target *-*-* } .-1 } */
+
+  /* Verify the implementationm doesn't ICE.  */
+  b = __builtin_has_attribute (foobar, aligned);  /* { dg-error ".foobar. \(undeclared|was not declared\)" } */
+
+  b = __builtin_has_attribute (1, 2, 3);     /* { dg-error "expected identifier" } */
+  b = __builtin_has_attribute (int, 1 + 2);  /* { dg-error "expected identifier" } */
+  b = __builtin_has_attribute (2, "aligned"); /* { dg-error "expected identifier" } */
+}
+
+/* Exercise syntactically valid arguments applied in invalid ways.  */
+
+void test_invalid_arguments (void)
+{
+  b = has_attr (fnone, align);        /* { dg-error "unknown attribute .align." } */
+  b = has_attr (b, aligned__);        /* { dg-error "unknown attribute .aligned__." } */
+  b = has_attr (fnone, aligned (3));  /* { dg-error "alignment .3. is not a positive power of 2" } */
+
+  /* Verify the out-of-bounds arguments are diagnosed and the result
+     of the built-in is false.  */
+  A (0, fnone, alloc_size (1));       /* { dg-warning "\\\[-Wattributes]" } */
+  A (0, fnone, alloc_size (2));       /* { dg-warning "\\\[-Wattributes]" } */
+
+  A (0, int, alloc_size (1));         /* { dg-warning ".alloc_size. attribute only applies to function types" } */
+
+  int i = 1;
+  A (0, i, alloc_size (1));           /* { dg-warning ".alloc_size. attribute only applies to function types" } */
+
+  A (0, faligned_8, aligned (i));     /* { dg-error "alignment is not an integer constant" } */
+
+  typedef ATTR ((aligned (2))) char CA2;
+  b = has_attr (CA2[2], aligned);     /* { dg-error "alignment of array elements is greater than element size" } */
+}
diff --git a/gcc/testsuite/gcc.dg/builtin-has-attribute.c b/gcc/testsuite/gcc.dg/builtin-has-attribute.c
new file mode 100644 (file)
index 0000000..8c11cf8
--- /dev/null
@@ -0,0 +1,45 @@
+/* Verify that defining a type in __builtin_has_attribute triggers
+   the expected -Wc++-compat warning and evaluates as expected.
+   Also verify that the expression in __builtin_has_attribute is
+   not evaluated.
+
+  { dg-do run }
+  { dg-options "-O2 -Wall -Wc++-compat" }  */
+
+#define ATTR(list) __attribute__ (list)
+
+#define A(expect, sym, attr)                                           \
+  typedef int Assert [1 - 2 * !(__builtin_has_attribute (sym, attr) == expect)]
+
+int nfails;
+
+#define assert(expr)                                           \
+  ((expr)                                                      \
+   ? (void)0                                                   \
+   : (__builtin_printf ("Assertion failed on line %i: %s\n",   \
+                       __LINE__, #expr),                       \
+      ++nfails))
+
+A (0, struct A { int i; }, aligned);   /* { dg-warning "expression is invalid in C\\\+\\\+" } */
+A (1, struct ATTR ((aligned)) B { int i; }, aligned);   /* { dg-warning "expression is invalid in C\\\+\\\+" } */
+
+
+int f (void)
+{
+  __builtin_abort ();
+}
+
+int n = 1;
+
+int main (void)
+{
+  assert (0 == __builtin_has_attribute (int[n++], aligned));
+  assert (1 == __builtin_has_attribute (ATTR ((aligned)) int[n++], aligned));
+  assert (1 == __builtin_has_attribute (ATTR ((aligned)) int[f ()], aligned));
+  assert (1 == 1);
+
+  if (nfails)
+    __builtin_abort ();
+
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/i386/builtin-has-attribute.c b/gcc/testsuite/gcc.target/i386/builtin-has-attribute.c
new file mode 100644 (file)
index 0000000..2de1ba3
--- /dev/null
@@ -0,0 +1,54 @@
+/* Verify __builtin_has_attribute return value for i386 function attributes.
+   { dg-do compile }
+   { dg-options "-Wall -ftrack-macro-expansion=0" }
+   { dg-options "-Wall -Wno-narrowing -Wno-unused -ftrack-macro-expansion=0" { target c++ } }  */
+
+#define ATTR(...) __attribute__ ((__VA_ARGS__))
+
+#define A(expect, sym, attr)                                           \
+  typedef int Assert [1 - 2 * !(__builtin_has_attribute (sym, attr) == expect)]
+
+void fnone (void);
+
+
+ATTR (interrupt) void finterrupt (void*);
+ATTR (interrupt, naked) void fnaked_interrupt (void*);
+
+A (0, fnone, interrupt);
+A (1, finterrupt, interrupt);
+A (1, fnaked_interrupt, interrupt);
+A (1, fnaked_interrupt, naked);
+
+
+ATTR (naked) void fnaked (void);
+
+A (0, fnone, naked);
+A (1, fnaked, naked);
+
+
+ATTR (no_caller_saved_registers) void fnsr (int);
+
+A (0, fnone, no_caller_saved_registers);
+A (1, fnsr, no_caller_saved_registers);
+
+
+ATTR (target ("abm")) void ftarget_abm (void);
+ATTR (target ("mmx")) void ftarget_mmx (void);
+ATTR (target ("mmx"), target ("sse")) void ftarget_mmx_sse (void);
+
+A (0, fnone, target);
+A (0, fnone, target ("abm"));
+A (0, fnone, target ("mmx"));
+
+A (1, ftarget_abm, target);
+A (0, ftarget_abm, target ("no-abm"));
+A (1, ftarget_abm, target ("abm"));
+
+A (1, ftarget_mmx, target);
+A (0, ftarget_mmx, target ("no-mmx"));
+A (1, ftarget_mmx, target ("mmx"));
+
+A (1, ftarget_mmx_sse, target);
+A (0, ftarget_mmx_sse, target ("no-mmx"));
+A (1, ftarget_mmx_sse, target ("mmx"));
+A (1, ftarget_mmx_sse, target ("sse"));