aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog4
-rw-r--r--gcc/c-family/ChangeLog5
-rw-r--r--gcc/c-family/c-attribs.c2
-rw-r--r--gcc/c-family/c-common.h1
-rw-r--r--gcc/c-family/c-lex.c4
-rw-r--r--gcc/cp/ChangeLog15
-rw-r--r--gcc/cp/cp-gimplify.c93
-rw-r--r--gcc/cp/cp-tree.h2
-rw-r--r--gcc/cp/decl.c2
-rw-r--r--gcc/cp/parser.c41
-rw-r--r--gcc/cp/pt.c12
-rw-r--r--gcc/cp/tree.c30
-rw-r--r--gcc/gimplify.c10
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/attr-likely1.C38
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/attr-likely2.C12
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/attr-likely3.C8
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/attr-likely4.C19
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/feat-cxx2a.C12
18 files changed, 296 insertions, 14 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 713f1c3..4b87c43 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -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
diff --git a/gcc/c-family/ChangeLog b/gcc/c-family/ChangeLog
index ed700f8..db46542 100644
--- a/gcc/c-family/ChangeLog
+++ b/gcc/c-family/ChangeLog
@@ -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
diff --git a/gcc/c-family/c-attribs.c b/gcc/c-family/c-attribs.c
index c9afa1f..88b24cd 100644
--- a/gcc/c-family/c-attribs.c
+++ b/gcc/c-family/c-attribs.c
@@ -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),
diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h
index 8eeeba7..4aa6142 100644
--- a/gcc/c-family/c-common.h
+++ b/gcc/c-family/c-common.h
@@ -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 {
diff --git a/gcc/c-family/c-lex.c b/gcc/c-family/c-lex.c
index d979a97..93a6f16 100644
--- a/gcc/c-family/c-lex.c
+++ b/gcc/c-family/c-lex.c
@@ -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;
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index b8a7437..d0a344e 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -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
diff --git a/gcc/cp/cp-gimplify.c b/gcc/cp/cp-gimplify.c
index eb761b1..5cb54ad 100644
--- a/gcc/cp/cp-gimplify.c
+++ b/gcc/cp/cp-gimplify.c
@@ -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"
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index a5c9e5b..edb9494 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -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);
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 7d63bbe..1eee29e 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -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));
}
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index 92a4f96..215c5fb 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -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))
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 66e8f6f..a0d899f 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -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)));
diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c
index 10b2cfb..97074df 100644
--- a/gcc/cp/tree.c
+++ b/gcc/cp/tree.c
@@ -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 }
};
diff --git a/gcc/gimplify.c b/gcc/gimplify.c
index 87082ad..40fbaa2 100644
--- a/gcc/gimplify.c
+++ b/gcc/gimplify.c
@@ -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
index 0000000..43de249
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/attr-likely1.C
@@ -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
index 0000000..6c59610
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/attr-likely2.C
@@ -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
index 0000000..bb1265d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/attr-likely3.C
@@ -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
index 0000000..bf0dc4c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/attr-likely4.C
@@ -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;
+}
diff --git a/gcc/testsuite/g++.dg/cpp2a/feat-cxx2a.C b/gcc/testsuite/g++.dg/cpp2a/feat-cxx2a.C
index dba7717..b80cc34 100644
--- a/gcc/testsuite/g++.dg/cpp2a/feat-cxx2a.C
+++ b/gcc/testsuite/g++.dg/cpp2a/feat-cxx2a.C
@@ -456,6 +456,18 @@
# 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