Implement P0479R5, [[likely]] and [[unlikely]].
authorJason Merrill <jason@redhat.com>
Fri, 16 Nov 2018 21:49:42 +0000 (16:49 -0500)
committerJason Merrill <jason@gcc.gnu.org>
Fri, 16 Nov 2018 21:49:42 +0000 (16:49 -0500)
[[likely]] and [[unlikely]] are equivalent to the GNU hot/cold attributes,
except that they can be applied to arbitrary statements as well as labels;
this is most likely to be useful for marking if/else branches as likely or
unlikely.  Conveniently, PREDICT_EXPR fits the bill nicely as a
representation.

I also had to fix marking case labels as hot/cold, which didn't work before.
Which then required me to force __attribute ((fallthrough)) to apply to the
statement rather than the label.

gcc/
* gimplify.c (gimplify_case_label_expr): Handle hot/cold attributes.
gcc/c-family/
* c-lex.c (c_common_has_attribute): Handle likely/unlikely.
* c-attribs.c (attr_cold_hot_exclusions): Make public.
gcc/cp/
* tree.c (handle_likeliness_attribute): New.
(std_attribute_table): Add likely/unlikely.
* cp-gimplify.c (lookup_hotness_attribute, remove_hotness_attribute)
(process_stmt_hotness_attribute, first_stmt): New.
(genericize_if_stmt): Check for duplicate predictions.
* parser.c (cp_parser_statement): Call
process_stmt_hotness_attribute.
(cp_parser_label_for_labeled_statement): Apply attributes to case.
* decl.c (finish_case_label): Give label in template type void.
* pt.c (tsubst_expr) [CASE_LABEL_EXPR]: Copy attributes.
[PREDICT_EXPR]: Handle.

From-SVN: r266223

18 files changed:
gcc/ChangeLog
gcc/c-family/ChangeLog
gcc/c-family/c-attribs.c
gcc/c-family/c-common.h
gcc/c-family/c-lex.c
gcc/cp/ChangeLog
gcc/cp/cp-gimplify.c
gcc/cp/cp-tree.h
gcc/cp/decl.c
gcc/cp/parser.c
gcc/cp/pt.c
gcc/cp/tree.c
gcc/gimplify.c
gcc/testsuite/g++.dg/cpp2a/attr-likely1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp2a/attr-likely2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp2a/attr-likely3.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp2a/attr-likely4.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp2a/feat-cxx2a.C

index 713f1c367fb03f5898901f51a09421c6de2bfe0e..4b87c43a2ea4a5873c0cac14336d5873be34dfa3 100644 (file)
@@ -1,3 +1,7 @@
+2018-11-12  Jason Merrill  <jason@redhat.com>
+
+       * gimplify.c (gimplify_case_label_expr): Handle hot/cold attributes.
+
 2018-11-16  Michael Meissner  <meissner@linux.ibm.com>
 
        * config/rs6000/constraints.md (wF constraint): Remove power9
index ed700f8decac7e5b1c4b4816d8b2f733794d3f5a..db46542105101b8203ecd7a8486ed11d65d967d5 100644 (file)
@@ -1,3 +1,8 @@
+2018-11-16  Jason Merrill  <jason@redhat.com>
+
+       * c-lex.c (c_common_has_attribute): Handle likely/unlikely.
+       * c-attribs.c (attr_cold_hot_exclusions): Make public.
+
 2018-11-16  Jakub Jelinek  <jakub@redhat.com>
 
        PR middle-end/87854
index c9afa1f78f416c921161f9f0fc38fb6eb7c6c569..88b24cd6cd49f14bfe24dc1f45c92ad4b702d48e 100644 (file)
@@ -163,7 +163,7 @@ static const struct attribute_spec::exclusions attr_aligned_exclusions[] =
   ATTR_EXCL (NULL, false, false, false)
 };
 
-static const struct attribute_spec::exclusions attr_cold_hot_exclusions[] =
+extern const struct attribute_spec::exclusions attr_cold_hot_exclusions[] =
 {
   ATTR_EXCL ("cold", true, true, true),
   ATTR_EXCL ("hot", true, true, true),
index 8eeeba7531921f3dd19dff565989532b32120445..4aa614261142e4a6716cc7182fa731bc4bf586d8 100644 (file)
@@ -1330,6 +1330,7 @@ extern int parse_tm_stmt_attr (tree, int);
 extern int tm_attr_to_mask (tree);
 extern tree tm_mask_to_attr (int);
 extern tree find_tm_attribute (tree);
+extern const struct attribute_spec::exclusions attr_cold_hot_exclusions[];
 
 /* A bitmap of flags to positional_argument.  */
 enum posargflags {
index d979a970459a6567f5135c53740c196b5acf23b3..93a6f1660c4cbe3a77166c74c70a8c1360e32ba5 100644 (file)
@@ -356,7 +356,9 @@ c_common_has_attribute (cpp_reader *pfile)
                       || is_attribute_p ("nodiscard", attr_name)
                       || is_attribute_p ("fallthrough", attr_name))
                result = 201603;
-             else if (is_attribute_p ("no_unique_address", attr_name))
+             else if (is_attribute_p ("no_unique_address", attr_name)
+                      || is_attribute_p ("likely", attr_name)
+                      || is_attribute_p ("unlikely", attr_name))
                result = 201803;
              if (result)
                attr_name = NULL_TREE;
index b8a74376fb95bb9406f4bcf2b1e942d4501fabf1..d0a344eadcaf1ad35fde8705b2445a48be598d96 100644 (file)
@@ -1,3 +1,18 @@
+2018-11-16  Jason Merrill  <jason@redhat.com>
+
+       Implement P0479R5, [[likely]] and [[unlikely]].
+       * tree.c (handle_likeliness_attribute): New.
+       (std_attribute_table): Add likely/unlikely.
+       * cp-gimplify.c (lookup_hotness_attribute, remove_hotness_attribute)
+       (process_stmt_hotness_attribute, first_stmt): New.
+       (genericize_if_stmt): Check for duplicate predictions.
+       * parser.c (cp_parser_statement): Call
+       process_stmt_hotness_attribute.
+       (cp_parser_label_for_labeled_statement): Apply attributes to case.
+       * decl.c (finish_case_label): Give label in template type void.
+       * pt.c (tsubst_expr) [CASE_LABEL_EXPR]: Copy attributes.
+       [PREDICT_EXPR]: Handle.
+
 2018-11-16  Nathan Sidwell  <nathan@acm.org>
 
        Remove ovl_used, it is no longer needed
index eb761b118a17632af0ff322f9a93926f2ee95a99..5cb54adf60f96f944575d1753ee733016d227b3e 100644 (file)
@@ -34,6 +34,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "stringpool.h"
 #include "attribs.h"
 #include "asan.h"
+#include "gcc-rich-location.h"
 
 /* Forward declarations.  */
 
@@ -158,6 +159,26 @@ genericize_eh_spec_block (tree *stmt_p)
   TREE_NO_WARNING (TREE_OPERAND (*stmt_p, 1)) = true;
 }
 
+/* Return the first non-compound statement in STMT.  */
+
+tree
+first_stmt (tree stmt)
+{
+  switch (TREE_CODE (stmt))
+    {
+    case STATEMENT_LIST:
+      if (tree_statement_list_node *p = STATEMENT_LIST_HEAD (stmt))
+       return first_stmt (p->stmt);
+      return void_node;
+
+    case BIND_EXPR:
+      return first_stmt (BIND_EXPR_BODY (stmt));
+
+    default:
+      return stmt;
+    }
+}
+
 /* Genericize an IF_STMT by turning it into a COND_EXPR.  */
 
 static void
@@ -171,6 +192,24 @@ genericize_if_stmt (tree *stmt_p)
   then_ = THEN_CLAUSE (stmt);
   else_ = ELSE_CLAUSE (stmt);
 
+  if (then_ && else_)
+    {
+      tree ft = first_stmt (then_);
+      tree fe = first_stmt (else_);
+      br_predictor pr;
+      if (TREE_CODE (ft) == PREDICT_EXPR
+         && TREE_CODE (fe) == PREDICT_EXPR
+         && (pr = PREDICT_EXPR_PREDICTOR (ft)) == PREDICT_EXPR_PREDICTOR (fe)
+         && (pr == PRED_HOT_LABEL || pr == PRED_COLD_LABEL))
+       {
+         gcc_rich_location richloc (EXPR_LOC_OR_LOC (ft, locus));
+         richloc.add_range (EXPR_LOC_OR_LOC (fe, locus));
+         warning_at (&richloc, OPT_Wattributes,
+                     "both branches of %<if%> statement marked as %qs",
+                     predictor_name (pr));
+       }
+    }
+
   if (!then_)
     then_ = build_empty_stmt (locus);
   if (!else_)
@@ -2674,4 +2713,58 @@ cp_fold (tree x)
   return x;
 }
 
+/* Look up either "hot" or "cold" in attribute list LIST.  */
+
+tree
+lookup_hotness_attribute (tree list)
+{
+  for (; list; list = TREE_CHAIN (list))
+    {
+      tree name = get_attribute_name (list);
+      if (is_attribute_p ("hot", name)
+         || is_attribute_p ("cold", name)
+         || is_attribute_p ("likely", name)
+         || is_attribute_p ("unlikely", name))
+       break;
+    }
+  return list;
+}
+
+/* Remove both "hot" and "cold" attributes from LIST.  */
+
+static tree
+remove_hotness_attribute (tree list)
+{
+  list = remove_attribute ("hot", list);
+  list = remove_attribute ("cold", list);
+  list = remove_attribute ("likely", list);
+  list = remove_attribute ("unlikely", list);
+  return list;
+}
+
+/* If [[likely]] or [[unlikely]] appear on this statement, turn it into a
+   PREDICT_EXPR.  */
+
+tree
+process_stmt_hotness_attribute (tree std_attrs)
+{
+  if (std_attrs == error_mark_node)
+    return std_attrs;
+  if (tree attr = lookup_hotness_attribute (std_attrs))
+    {
+      tree name = get_attribute_name (attr);
+      bool hot = (is_attribute_p ("hot", name)
+                 || is_attribute_p ("likely", name));
+      tree pred = build_predict_expr (hot ? PRED_HOT_LABEL : PRED_COLD_LABEL,
+                                     hot ? TAKEN : NOT_TAKEN);
+      SET_EXPR_LOCATION (pred, input_location);
+      add_stmt (pred);
+      if (tree other = lookup_hotness_attribute (TREE_CHAIN (attr)))
+       warning (OPT_Wattributes, "ignoring attribute %qE after earlier %qE",
+                get_attribute_name (other), name);
+      std_attrs = remove_hotness_attribute (std_attrs);
+    }
+  return std_attrs;
+}
+
 #include "gt-cp-cp-gimplify.h"
index a5c9e5b20806dd67f5b355fcf109cb89050c9101..edb94940098474198267b4fedf1d6a6db7ef8654 100644 (file)
@@ -7541,6 +7541,8 @@ extern bool cxx_omp_disregard_value_expr  (tree, bool);
 extern void cp_fold_function                   (tree);
 extern tree cp_fully_fold                      (tree);
 extern void clear_fold_cache                   (void);
+extern tree lookup_hotness_attribute           (tree);
+extern tree process_stmt_hotness_attribute     (tree);
 
 /* in name-lookup.c */
 extern tree strip_using_decl                    (tree);
index 7d63bbe7f1bb8b43122742bb392c0f1bda9f2e63..1eee29e0d59852872387c381154f10c67d5275e2 100644 (file)
@@ -3624,7 +3624,7 @@ finish_case_label (location_t loc, tree low_value, tree high_value)
 
       /* For templates, just add the case label; we'll do semantic
         analysis at instantiation-time.  */
-      label = build_decl (loc, LABEL_DECL, NULL_TREE, NULL_TREE);
+      label = build_decl (loc, LABEL_DECL, NULL_TREE, void_type_node);
       return add_stmt (build_case_label (low_value, high_value, label));
     }
 
index 92a4f96c6b75d27b44e9fa3a6e2bbffda317e9cb..215c5fb9983287ef2899eb78a9c9294b1c42c4e8 100644 (file)
@@ -10880,6 +10880,7 @@ cp_parser_statement (cp_parser* parser, tree in_statement_expr,
   /* Peek at the next token.  */
   token = cp_lexer_peek_token (parser->lexer);
   /* Remember the location of the first token in the statement.  */
+  cp_token *statement_token = token;
   statement_location = token->location;
   add_debug_begin_stmt (statement_location);
   /* If this is a keyword, then that will often determine what kind of
@@ -10901,12 +10902,14 @@ cp_parser_statement (cp_parser* parser, tree in_statement_expr,
 
        case RID_IF:
        case RID_SWITCH:
+         std_attrs = process_stmt_hotness_attribute (std_attrs);
          statement = cp_parser_selection_statement (parser, if_p, chain);
          break;
 
        case RID_WHILE:
        case RID_DO:
        case RID_FOR:
+         std_attrs = process_stmt_hotness_attribute (std_attrs);
          statement = cp_parser_iteration_statement (parser, if_p, false, 0);
          break;
 
@@ -10914,6 +10917,7 @@ cp_parser_statement (cp_parser* parser, tree in_statement_expr,
        case RID_CONTINUE:
        case RID_RETURN:
        case RID_GOTO:
+         std_attrs = process_stmt_hotness_attribute (std_attrs);
          statement = cp_parser_jump_statement (parser);
          break;
 
@@ -10923,15 +10927,24 @@ cp_parser_statement (cp_parser* parser, tree in_statement_expr,
        case RID_AT_FINALLY:
        case RID_AT_SYNCHRONIZED:
        case RID_AT_THROW:
+         std_attrs = process_stmt_hotness_attribute (std_attrs);
          statement = cp_parser_objc_statement (parser);
          break;
 
        case RID_TRY:
+         std_attrs = process_stmt_hotness_attribute (std_attrs);
          statement = cp_parser_try_block (parser);
          break;
 
        case RID_NAMESPACE:
          /* This must be a namespace alias definition.  */
+         if (std_attrs != NULL_TREE)
+           {
+             /*  Attributes should be parsed as part of the the
+                 declaration, so let's un-parse them.  */
+             saved_tokens.rollback();
+             std_attrs = NULL_TREE;
+           }
          cp_parser_declaration_statement (parser);
          return;
          
@@ -10940,9 +10953,11 @@ cp_parser_statement (cp_parser* parser, tree in_statement_expr,
        case RID_SYNCHRONIZED:
        case RID_ATOMIC_NOEXCEPT:
        case RID_ATOMIC_CANCEL:
+         std_attrs = process_stmt_hotness_attribute (std_attrs);
          statement = cp_parser_transaction (parser, token);
          break;
        case RID_TRANSACTION_CANCEL:
+         std_attrs = process_stmt_hotness_attribute (std_attrs);
          statement = cp_parser_transaction_cancel (parser);
          break;
 
@@ -11001,12 +11016,9 @@ cp_parser_statement (cp_parser* parser, tree in_statement_expr,
       if (cp_lexer_next_token_is_not (parser->lexer, CPP_SEMICOLON))
        {
          if (std_attrs != NULL_TREE)
-           {
-             /*  Attributes should be parsed as part of the the
-                 declaration, so let's un-parse them.  */
-             saved_tokens.rollback();
-             std_attrs = NULL_TREE;
-           }
+           /* Attributes should be parsed as part of the declaration,
+              so let's un-parse them.  */
+           saved_tokens.rollback();
 
          cp_parser_parse_tentatively (parser);
          /* Try to parse the declaration-statement.  */
@@ -11014,11 +11026,16 @@ cp_parser_statement (cp_parser* parser, tree in_statement_expr,
          /* If that worked, we're done.  */
          if (cp_parser_parse_definitely (parser))
            return;
+         /* It didn't work, restore the post-attribute position.  */
+         if (std_attrs)
+           cp_lexer_set_token_position (parser->lexer, statement_token);
        }
       /* All preceding labels have been parsed at this point.  */
       if (loc_after_labels != NULL)
        *loc_after_labels = statement_location;
 
+      std_attrs = process_stmt_hotness_attribute (std_attrs);
+
       /* Look for an expression-statement instead.  */
       statement = cp_parser_expression_statement (parser, in_statement_expr);
 
@@ -11131,7 +11148,10 @@ cp_parser_label_for_labeled_statement (cp_parser* parser, tree attributes)
          {
            tree l = finish_case_label (token->location, expr, expr_hi);
            if (l && TREE_CODE (l) == CASE_LABEL_EXPR)
-             FALLTHROUGH_LABEL_P (CASE_LABEL (l)) = fallthrough_p;
+             {
+               label = CASE_LABEL (l);
+               FALLTHROUGH_LABEL_P (label) = fallthrough_p;
+             }
          }
        else
          error_at (token->location,
@@ -11148,7 +11168,10 @@ cp_parser_label_for_labeled_statement (cp_parser* parser, tree attributes)
        {
          tree l = finish_case_label (token->location, NULL_TREE, NULL_TREE);
          if (l && TREE_CODE (l) == CASE_LABEL_EXPR)
-           FALLTHROUGH_LABEL_P (CASE_LABEL (l)) = fallthrough_p;
+             {
+               label = CASE_LABEL (l);
+               FALLTHROUGH_LABEL_P (label) = fallthrough_p;
+             }
        }
       else
        error_at (token->location, "case label not within a switch statement");
@@ -11178,6 +11201,8 @@ cp_parser_label_for_labeled_statement (cp_parser* parser, tree attributes)
       cp_parser_parse_tentatively (parser);
       attrs = cp_parser_gnu_attributes_opt (parser);
       if (attrs == NULL_TREE
+         /* And fallthrough always binds to the expression-statement.  */
+         || attribute_fallthrough_p (attrs)
          || cp_lexer_next_token_is_not (parser->lexer, CPP_SEMICOLON))
        cp_parser_abort_tentative_parse (parser);
       else if (!cp_parser_parse_definitely (parser))
index 66e8f6fed1f46077906ad8a54cbbdf38c2f96f21..a0d899f594b6cffa6462979d0852af7d9d8484ab 100644 (file)
@@ -17175,12 +17175,17 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl,
 
     case CASE_LABEL_EXPR:
       {
+       tree decl = CASE_LABEL (t);
        tree low = RECUR (CASE_LOW (t));
        tree high = RECUR (CASE_HIGH (t));
        tree l = finish_case_label (EXPR_LOCATION (t), low, high);
        if (l && TREE_CODE (l) == CASE_LABEL_EXPR)
-         FALLTHROUGH_LABEL_P (CASE_LABEL (l))
-           = FALLTHROUGH_LABEL_P (CASE_LABEL (t));
+         {
+           tree label = CASE_LABEL (l);
+           FALLTHROUGH_LABEL_P (label) = FALLTHROUGH_LABEL_P (decl);
+           if (DECL_ATTRIBUTES (decl) != NULL_TREE)
+             cplus_decl_attributes (&label, DECL_ATTRIBUTES (decl), 0);
+         }
       }
       break;
 
@@ -17731,6 +17736,9 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl,
                          RECUR (TREE_OPERAND (t, 1)),
                          RECUR (TREE_OPERAND (t, 2))));
 
+    case PREDICT_EXPR:
+      RETURN (add_stmt (copy_node (t)));
+
     default:
       gcc_assert (!STATEMENT_CODE_P (TREE_CODE (t)));
 
index 10b2cfbdf029b521ea375d17e385fd5739b4981e..97074dfab563a53611bab7d248cdef580d120308 100644 (file)
@@ -4403,6 +4403,32 @@ handle_no_unique_addr_attribute (tree* node,
   return NULL_TREE;
 }
 
+/* The C++20 [[likely]] and [[unlikely]] attributes on labels map to the GNU
+   hot/cold attributes.  */
+
+static tree
+handle_likeliness_attribute (tree *node, tree name, tree args,
+                            int flags, bool *no_add_attrs)
+{
+  *no_add_attrs = true;
+  if (TREE_CODE (*node) == LABEL_DECL
+      || TREE_CODE (*node) == FUNCTION_DECL)
+    {
+      if (args)
+       warning (OPT_Wattributes, "%qE attribute takes no arguments", name);
+      tree bname = (is_attribute_p ("likely", name)
+                   ? get_identifier ("hot") : get_identifier ("cold"));
+      if (TREE_CODE (*node) == FUNCTION_DECL)
+       warning (OPT_Wattributes, "ISO C++ %qE attribute does not apply to "
+                "functions; treating as %<[[gnu::%E]]%>", name, bname);
+      tree battr = build_tree_list (bname, NULL_TREE);
+      decl_attributes (node, battr, flags);
+      return NULL_TREE;
+    }
+  else
+    return error_mark_node;
+}
+
 /* Table of valid C++ attributes.  */
 const struct attribute_spec cxx_attribute_table[] =
 {
@@ -4426,6 +4452,10 @@ const struct attribute_spec std_attribute_table[] =
     handle_nodiscard_attribute, NULL },
   { "no_unique_address", 0, 0, true, false, false, false,
     handle_no_unique_addr_attribute, NULL },
+  { "likely", 0, 0, false, false, false, false,
+    handle_likeliness_attribute, attr_cold_hot_exclusions },
+  { "unlikely", 0, 0, false, false, false, false,
+    handle_likeliness_attribute, attr_cold_hot_exclusions },
   { NULL, 0, 0, false, false, false, false, NULL, NULL }
 };
 
index 87082ad10d2a907b2b309ad16debecd9917d16dc..40fbaa2c523177031e50993b5575f821cf519227 100644 (file)
@@ -2511,11 +2511,19 @@ gimplify_case_label_expr (tree *expr_p, gimple_seq *pre_p)
     if (ctxp->case_labels.exists ())
       break;
 
-  label_stmt = gimple_build_label (CASE_LABEL (*expr_p));
+  tree label = CASE_LABEL (*expr_p);
+  label_stmt = gimple_build_label (label);
   gimple_set_location (label_stmt, EXPR_LOCATION (*expr_p));
   ctxp->case_labels.safe_push (*expr_p);
   gimplify_seq_add_stmt (pre_p, label_stmt);
 
+  if (lookup_attribute ("cold", DECL_ATTRIBUTES (label)))
+    gimple_seq_add_stmt (pre_p, gimple_build_predict (PRED_COLD_LABEL,
+                                                     NOT_TAKEN));
+  else if (lookup_attribute ("hot", DECL_ATTRIBUTES (label)))
+    gimple_seq_add_stmt (pre_p, gimple_build_predict (PRED_HOT_LABEL,
+                                                     TAKEN));
+
   return GS_ALL_DONE;
 }
 
diff --git a/gcc/testsuite/g++.dg/cpp2a/attr-likely1.C b/gcc/testsuite/g++.dg/cpp2a/attr-likely1.C
new file mode 100644 (file)
index 0000000..43de249
--- /dev/null
@@ -0,0 +1,38 @@
+// { dg-do compile { target c++2a } }
+// { dg-additional-options -fdump-tree-gimple }
+// { dg-final { scan-tree-dump-times "hot label" 5 "gimple" } }
+// { dg-final { scan-tree-dump-times "cold label" 3 "gimple" } }
+
+bool b;
+
+template <class T> int f()
+{
+  if (b)
+    [[likely]] return 0;
+  else
+    [[unlikely]] flabel: return 1;
+  switch (b)
+    {
+      [[likely]] case true: break;
+    };
+  return 1;
+}
+
+int main()
+{
+  if (b)
+    [[likely]] return 0;
+  else if (b)
+    [[unlikely]] elabel:
+      return 1;
+  else
+    [[likely]] b = false;
+
+  f<int>();
+
+  switch (b)
+    {
+      [[likely]] case true: break;
+      [[unlikely]] case false: break;
+    };
+}
diff --git a/gcc/testsuite/g++.dg/cpp2a/attr-likely2.C b/gcc/testsuite/g++.dg/cpp2a/attr-likely2.C
new file mode 100644 (file)
index 0000000..6c59610
--- /dev/null
@@ -0,0 +1,12 @@
+// { dg-do compile { target c++2a } }
+
+bool b;
+int main()
+{
+  if (b)
+    [[likely, likely]] b;      // { dg-warning "ignoring" }
+  else
+    [[unlikely]] [[likely]] b; // { dg-warning "ignoring" }
+
+  [[likely, unlikely]] lab:;   // { dg-warning "ignoring" }
+}
diff --git a/gcc/testsuite/g++.dg/cpp2a/attr-likely3.C b/gcc/testsuite/g++.dg/cpp2a/attr-likely3.C
new file mode 100644 (file)
index 0000000..bb1265d
--- /dev/null
@@ -0,0 +1,8 @@
+// { dg-do compile { target c++2a } }
+
+[[likely]] void f() { }                // { dg-warning "function" }
+
+int main()
+{
+  f();
+}
diff --git a/gcc/testsuite/g++.dg/cpp2a/attr-likely4.C b/gcc/testsuite/g++.dg/cpp2a/attr-likely4.C
new file mode 100644 (file)
index 0000000..bf0dc4c
--- /dev/null
@@ -0,0 +1,19 @@
+// { dg-do compile { target c++2a } }
+
+int a, b, c;
+
+void
+__attribute__((noinline))
+bar()
+{
+  if (a == 123)
+    [[likely]] c = 5;          // { dg-warning "both" }
+  else
+    [[likely]] b = 77;
+}
+
+int main()
+{
+  bar ();
+  return 0;
+}
index dba77179b82499e7516a1e062e3121501bfc610e..b80cc34236468ca72fc50cbaf432f6d5cacbbe00 100644 (file)
 #    error "__has_cpp_attribute(no_unique_address) != 201803"
 #  endif
 
+#  if ! __has_cpp_attribute(likely)
+#    error "__has_cpp_attribute(likely)"
+#  elif __has_cpp_attribute(likely) != 201803
+#    error "__has_cpp_attribute(likely) != 201803"
+#  endif
+
+#  if ! __has_cpp_attribute(unlikely)
+#    error "__has_cpp_attribute(unlikely)"
+#  elif __has_cpp_attribute(unlikely) != 201803
+#    error "__has_cpp_attribute(unlikely) != 201803"
+#  endif
+
 #else
 #  error "__has_cpp_attribute"
 #endif