diff --git a/gcc/c-family/c-attribs.cc b/gcc/c-family/c-attribs.cc
index e2792ca6898..090108ad94c 100644
--- a/gcc/c-family/c-attribs.cc
+++ b/gcc/c-family/c-attribs.cc
@@ -452,10 +452,10 @@ const struct attribute_spec
c_common_attribute_table[] =
   { "alloc_size",      1, 2, false, true, true, false,
       handle_alloc_size_attribute,
                       attr_alloc_exclusions },
-  { "cold",                   0, 0, true,  false, false, false,
+  { "cold",      0, 0, false,  false, false, false,
       handle_cold_attribute,
                       attr_cold_hot_exclusions },
-  { "hot",                    0, 0, true,  false, false, false,
+  { "hot",      0, 0, false,  false, false, false,
       handle_hot_attribute,
                       attr_cold_hot_exclusions },
   { "no_address_safety_analysis",
@@ -1110,6 +1110,17 @@ handle_hot_attribute (tree *node, tree name, tree
ARG_UNUSED (args),
     {
       /* Attribute hot processing is done later with lookup_attribute.  */
     }
+  else if ((TREE_CODE (*node) == RECORD_TYPE
+    || TREE_CODE (*node) == UNION_TYPE)
+  && c_dialect_cxx ())
+    {
+      /* Check conflict here as decl_attributes will otherwise only catch
+ it late at the function when the attribute is used on a class.  */
+      tree cold_attr = lookup_attribute ("cold", TYPE_ATTRIBUTES (*node));
+      if (cold_attr)
+ warning (OPT_Wattributes, "ignoring attribute %qE because it "
+ "conflicts with attribute %qs", name, "cold");
+    }
   else
     {
       warning (OPT_Wattributes, "%qE attribute ignored", name);
@@ -1131,6 +1142,17 @@ handle_cold_attribute (tree *node, tree name, tree
ARG_UNUSED (args),
     {
       /* Attribute cold processing is done later with lookup_attribute.  */
     }
+  else if ((TREE_CODE (*node) == RECORD_TYPE
+    || TREE_CODE (*node) == UNION_TYPE)
+  && c_dialect_cxx ())
+    {
+      /* Check conflict here as decl_attributes will otherwise only catch
+ it late at the function when the attribute is used on a class.  */
+      tree hot_attr = lookup_attribute ("hot", TYPE_ATTRIBUTES (*node));
+      if (hot_attr)
+ warning (OPT_Wattributes, "ignoring attribute %qE because it "
+    "conflicts with attribute %qs", name, "hot");
+    }
   else
     {
       warning (OPT_Wattributes, "%qE attribute ignored", name);
diff --git a/gcc/cp/class.cc b/gcc/cp/class.cc
index 778759237dc..9543ad69cb1 100644
--- a/gcc/cp/class.cc
+++ b/gcc/cp/class.cc
@@ -205,6 +205,7 @@ static tree get_vcall_index (tree, tree);
 static bool type_maybe_constexpr_default_constructor (tree);
 static bool type_maybe_constexpr_destructor (tree);
 static bool field_poverlapping_p (tree);
+static void propagate_class_warmth_attribute (tree);

 /* Set CURRENT_ACCESS_SPECIFIER based on the protection of DECL.  */

@@ -7733,6 +7734,48 @@ unreverse_member_declarations (tree t)
     }
 }

+/* Classes marked with hotness attributes propagate the attribute to
+   all methods.  */
+void
+propagate_class_warmth_attribute (tree t)
+{
+  tree class_has_cold_attr = lookup_attribute ("cold",
+   TYPE_ATTRIBUTES (t));
+  tree class_has_hot_attr = lookup_attribute ("hot",
+   TYPE_ATTRIBUTES (t));
+
+  if (class_has_cold_attr || class_has_hot_attr)
+    {
+      tree attr_cold_id = get_identifier ("cold");
+      tree attr_hot_id = get_identifier ("hot");
+
+      for (tree f = TYPE_FIELDS (t); f; f = DECL_CHAIN (f))
+ if (TREE_CODE (f) == FUNCTION_DECL)
+  {
+
+    /* Transparently ignore the new warmth attribute if it
+       conflicts with a present function attribute.  Otherwise
+       decl_attribute would still honour the present attribute,
+       but producing an undesired warning in the process.  */
+
+    if (class_has_cold_attr)
+      {
+ if (lookup_attribute ("hot",
+ DECL_ATTRIBUTES (f)) == NULL)
+  decl_attributes (&f,
+ tree_cons (attr_cold_id, NULL, NULL), 0);
+      }
+    else if (class_has_hot_attr)
+      {
+ if (lookup_attribute ("cold",
+ DECL_ATTRIBUTES (f)) == NULL)
+  decl_attributes (&f,
+ tree_cons (attr_hot_id, NULL, NULL), 0);
+      }
+  }
+    }
+}
+
 tree
 finish_struct (tree t, tree attributes)
 {
@@ -7866,6 +7909,10 @@ finish_struct (tree t, tree attributes)
       && !LAMBDA_TYPE_P (t))
     add_stmt (build_min (TAG_DEFN, t));

+  /* This must be done after all lazily declared special member funcitons
+     have been injected.  */
+  propagate_class_warmth_attribute (t);
+
   return t;
 }

diff --git a/gcc/testsuite/g++.dg/ext/attr-hotness.C
b/gcc/testsuite/g++.dg/ext/attr-hotness.C
new file mode 100644
index 00000000000..f9a6930304d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/attr-hotness.C
@@ -0,0 +1,16 @@
+/* { dg-do compile } */
+/* { dg-options "-O0 -Wattributes -fdump-tree-gimple" } */
+
+
+struct __attribute((cold)) A { __attribute((noinline, used)) void
foo(void) { } };
+
+struct __attribute((hot)) B { __attribute((noinline, used)) void foo(void)
{ } };
+
+struct __attribute((hot, cold)) C { __attribute((noinline, used)) void
foo(void) { } }; /* { dg-warning "ignoring attribute .cold. because it
conflicts with attribute .hot." } */
+
+struct __attribute((cold, hot)) D { __attribute((noinline, used)) void
foo(void) { } }; /* { dg-warning "ignoring attribute .hot. because it
