Re: [PATCH v5] c++: extend cold, hot attributes to classes

2023-09-06 Thread Javier Martinez via Gcc-patches
reminder: ready for commit?

- Javier

On Wed 23. Aug 2023 at 15:02, Javier Martinez <
javier.martinez.bugzi...@gmail.com> wrote:

> On Tue, Aug 22, 2023 at 7:50 PM Jason Merrill  wrote:
> > You still need an update to doc/extend.texi for this additional use of
> > the attribute.  Sorry I didn't think of that before.
>
> I should have caught that too, many thanks.
>
> Also addressed the formatting comments. Patch attached.
>
> Signed-off-by: Javier Martinez 
>


[PATCH v5] c++: extend cold, hot attributes to classes

2023-08-23 Thread Javier Martinez via Gcc-patches
On Tue, Aug 22, 2023 at 7:50 PM Jason Merrill  wrote:
> You still need an update to doc/extend.texi for this additional use of
> the attribute.  Sorry I didn't think of that before.

I should have caught that too, many thanks.

Also addressed the formatting comments. Patch attached.

Signed-off-by: Javier Martinez 
Signed-off-by: Javier Martinez 

gcc/c-family/ChangeLog:

* c-attribs.cc (handle_hot_attribute): remove warning on
RECORD_TYPE and UNION_TYPE when in c_dialect_xx.
(handle_cold_attribute): Likewise.

gcc/cp/ChangeLog:

* class.cc (propagate_class_warmth_attribute): New function.
(check_bases_and_members): propagate hot and cold attributes
to all FUNCTION_DECL when the record is marked hot or cold.
* cp-tree.h (maybe_propagate_warmth_attributes): New function.
* decl2.cc (maybe_propagate_warmth_attributes): New function.
* method.cc (lazily_declare_fn): propagate hot and cold
attributes to lazily declared functions when the record is
marked hot or cold.

gcc/ChangeLog:

* doc/extend.texi: Document attributes hot, cold on C++ types.

gcc/testsuite/ChangeLog:

* g++.dg/ext/attr-hotness.C: New test.

---
 gcc/c-family/c-attribs.cc   | 50 -
 gcc/cp/class.cc | 29 ++
 gcc/cp/cp-tree.h|  1 +
 gcc/cp/decl2.cc | 44 ++
 gcc/cp/method.cc|  6 +++
 gcc/doc/extend.texi | 37 +-
 gcc/testsuite/g++.dg/ext/attr-hotness.C | 16 
 7 files changed, 179 insertions(+), 4 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/ext/attr-hotness.C

diff --git a/gcc/c-family/c-attribs.cc b/gcc/c-family/c-attribs.cc
index e2792ca6898..5d83f54561d 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,29 @@ 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 ()
+	   && (flags & (int) ATTR_FLAG_TYPE_IN_PLACE))
+{
+  /* 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");
+	  *no_add_attrs = true;
+	}
+}
+  else if (flags & ((int) ATTR_FLAG_FUNCTION_NEXT
+		| (int) ATTR_FLAG_DECL_NEXT))
+{
+	/* Avoid applying the attribute to a function return type when
+	   used as:  void __attribute ((hot)) foo (void).  It will be
+	   passed to the function.  */
+	*no_add_attrs = true;
+}
   else
 {
   warning (OPT_Wattributes, "%qE attribute ignored", name);
@@ -1131,6 +1154,29 @@ 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 ()
+	   && (flags & (int) ATTR_FLAG_TYPE_IN_PLACE))
+{
+  /* 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");
+	  *no_add_attrs = true;
+	}
+}
+  else if (flags & ((int) ATTR_FLAG_FUNCTION_NEXT
+		| (int) ATTR_FLAG_DECL_NEXT))
+{
+	/* Avoid applying the attribute to a function return type when
+	   used as:  void __attribute ((cold)) foo (void).  It will be
+	   passed to the function.  */
+	*no_add_attrs = true;
+}
   else
 {
   warning (OPT_Wattributes, "%qE attribute ignored", name);
diff --git a/gcc/cp/class.cc b/gcc/cp/class.cc
index 778759237dc..0bb679f15be 100644
--- a/gcc/cp/class.cc
+++ b/gcc/cp/class.cc
@@ -205,6 +205,7 @@ sta

[PATCH v4] c++: extend cold, hot attributes to classes

2023-08-15 Thread Javier Martinez via Gcc-patches
On Mon, Aug 14, 2023 at 8:32 PM Jason Merrill  wrote:
> I think you also want to check for ATTR_FLAG_TYPE_IN_PLACE.
> [...]
> > +  propagate_class_warmth_attribute (t);
> Maybe call this in check_bases_and_members instead?

Yes, that is sensible. Done.

Thanks,
Javier

Signed-off-by: Javier Martinez 
Signed-off-by: Javier Martinez 

gcc/c-family/ChangeLog:

* c-attribs.cc (handle_hot_attribute): remove warning on RECORD_TYPE
and UNION_TYPE when in c_dialect_xx.
(handle_cold_attribute): Likewise.

gcc/cp/ChangeLog:

* class.cc (propagate_class_warmth_attribute): New function.
(check_bases_and_members): propagate hot and cold attributes
to all FUNCTION_DECL when the record is marked hot or cold.
* cp-tree.h (maybe_propagate_warmth_attributes): New function.
* decl2.cc (maybe_propagate_warmth_attributes): New function.
* method.cc (lazily_declare_fn): propagate hot and cold
attributes to lazily declared functions when the record is
marked hot or cold.

gcc/testsuite/ChangeLog:

* g++.dg/ext/attr-hotness.C: New test.
---
 gcc/c-family/c-attribs.cc   | 50 -
 gcc/cp/class.cc | 31 +++
 gcc/cp/cp-tree.h|  1 +
 gcc/cp/decl2.cc | 37 ++
 gcc/cp/method.cc|  6 +++
 gcc/testsuite/g++.dg/ext/attr-hotness.C | 16 
 6 files changed, 139 insertions(+), 2 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/ext/attr-hotness.C

diff --git a/gcc/c-family/c-attribs.cc b/gcc/c-family/c-attribs.cc
index e2792ca6898..25083d597c0 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,29 @@ 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 ()
+	   && (flags & (int) ATTR_FLAG_TYPE_IN_PLACE))
+{
+  /* 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");
+	  *no_add_attrs = true;
+	}
+}
+  else if (flags & ((int) ATTR_FLAG_FUNCTION_NEXT
+		| (int) ATTR_FLAG_DECL_NEXT))
+{
+	/* Avoid applying the attribute to a function return type when
+	   used as:  void __attribute ((hot)) foo (void).  It will be
+	   passed to the function.  */
+	*no_add_attrs = true;
+}
   else
 {
   warning (OPT_Wattributes, "%qE attribute ignored", name);
@@ -1131,6 +1154,29 @@ 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 ()
+	   && (flags & (int) ATTR_FLAG_TYPE_IN_PLACE))
+{
+  /* 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");
+	  *no_add_attrs = true;
+	}
+}
+  else if (flags & ((int) ATTR_FLAG_FUNCTION_NEXT
+		| (int) ATTR_FLAG_DECL_NEXT))
+{
+	/* Avoid applying the attribute to a function return type when
+	   used as:  void __attribute ((cold)) foo (void).  It will be
+	   passed to the function.  */
+	*no_add_attrs = true;
+}
   else
 {
   warning (OPT_Wattributes, "%qE attribute ignored", name);
diff --git a/gcc/cp/class.cc b/gcc/cp/class.cc
index 778759237dc..bf0b558967f 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_pov

[PATCH v3] c++: extend cold, hot attributes to classes

2023-08-11 Thread Javier Martinez via Gcc-patches
Hi Jason,

Regarding the initialization example - no, the set of classes that we
consider cold is more loosely defined.

On Thu, Aug 10, 2023 at 11:01 PM Jason Merrill  wrote:
> Yes, but that's because the implicit op== isn't declared lazily like
> some other special member functions (CLASSTYPE_LAZY_*/lazily_declare_fn)
> which can happen after the class is complete.

I see, thanks. I have fixed this now by injecting it directly from
lazily_declare_fn, works well. Doing it from grokclassfn instead seems to
be a nuisance because the explicit method attribute might be processed
after the class-propagated attribute is injected, which is the wrong way
around for the desired precedence.

> I think it would work to check for (flags & (ATTR_FLAG_FUNCTION_NEXT |
> ATTR_FLAG_DECL_NEXT)) and return without warning in that case.  You'd
> still set *no_add_attr.

Correct, done.

I have added the patch as an attachment, if it garbles it then I will use
git-send-email next time.

---
From 684ee3b19463fe7f447fbaa96a7b44522f1ce594 Mon Sep 17 00:00:00 2001
From: Javier Martinez 
Date: Thu, 10 Aug 2023 17:08:27 +0200
Subject: [PATCH v3] c++: extend cold, hot attributes to classes

Signed-off-by: Javier Martinez 

gcc/c-family/ChangeLog:

* c-attribs.cc (handle_hot_attribute): remove warning on RECORD_TYPE
and UNION_TYPE when in c_dialect_xx.
(handle_cold_attribute): Likewise

gcc/cp/ChangeLog:

* class.cc (propagate_class_warmth_attribute): New function.
(finish_struct): propagate hot and cold attributes to all
FUNCTION_DECL when the record is marked hot or cold.
* cp-tree.h (maybe_propagate_warmth_attributes): New function.
* decl2.cc (maybe_propagate_warmth_attributes): New function.
* method.cc (lazily_declare_fn): propagate hot and cold
attributes to lazily declared functions when the record is
marked hot or cold.

gcc/testsuite/ChangeLog:

* g++.dg/ext/attr-hotness.C: New test.

---
 gcc/c-family/c-attribs.cc   | 48 +++--
 gcc/cp/class.cc | 29 +++
 gcc/cp/cp-tree.h|  1 +
 gcc/cp/decl2.cc | 37 +++
 gcc/cp/method.cc|  6 
 gcc/testsuite/g++.dg/ext/attr-hotness.C | 16 +
 6 files changed, 135 insertions(+), 2 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/ext/attr-hotness.C

diff --git a/gcc/c-family/c-attribs.cc b/gcc/c-family/c-attribs.cc
index e2792ca6898..bfd2ff194b5 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,28 @@ 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");
+	  *no_add_attrs = true;
+	}
+}
+  else if (flags & ((int) ATTR_FLAG_FUNCTION_NEXT
+		| (int) ATTR_FLAG_DECL_NEXT))
+{
+	/* Avoid applying the attribute to a function return type when
+	   used as:  void __attribute ((hot)) foo (void).  It will be
+	   passed to the function.  */
+	*no_add_attrs = true;
+}
   else
 {
   warning (OPT_Wattributes, "%qE attribute ignored", name);
@@ -1131,6 +1153,28 @@ 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 "
+			"conf

[RFC PATCH v2] c++: extend cold, hot attributes to classes

2023-08-10 Thread Javier Martinez via Gcc-patches
Thanks for the comments, Jason.
v2: + Fix formatting, remove unnecessarily warning.

On Tue, Aug 8, 2023 at 10:28 PM Jason Merrill  wrote:
> Seems reasonable, but how do you expect this to be used?
We have large applications where some large classes are known to be used
only at startup. Marking every member function as cold is impractical so we
would mark those classes as cold.

> I think doing this here will miss lazily-declared special member
> functions; I wonder if you want to copy the attribute in grokclassfn
> instead?
I think they are being handled correctly with the current patch. Considered
the following program:

class __attribute((cold)) Foo {
public:
int m_x, m_y;
auto operator<=>(const Foo&) const = default;
};

int main(void) {
Foo a{1,1};
Foo b{1,2};

std::set s; // OK
s.insert(a); // OK

std::cout << std::boolalpha
<< (a == b) << ' '
<< (a != b) << ' '
<< (a <  b) << ' '
<< (a <= b) << ' '
<< (a >  b) << ' '
<< (a >= b) << ' '
<< std::endl;
}

Per the rules for any operator<=> overload, a defaulted <=> overload will
also allow the type to be compared with <, <=, >, and >=. If operator<=> is
defaulted and operator== is not declared at all, then operator== is
implicitly defaulted.
The GIMPLE dump shows:
> __attribute__((cold))
> struct strong_ordering Foo::operator<=> (const struct Foo * const this,
const struct Foo & D.64195)
> __attribute__((cold))
> bool Foo::operator== (const struct Foo * const this, const struct Foo &
D.64206)

I think this makes sense as add_implicitly_declared_members is called
before my injection via finish_struct_1 -> check_bases_and_members.

---

I would like some comment on the implications of:
-  { "cold",   0, 0, true,  false, false, false,
+  { "cold",  0, 0, false,  false, false, false,

As I am now introducing a new warning that I cannot explain in an old test:
testsuite/g++.dg/Wmissing-attributes.C:55:22: warning: 'hot' attribute
ignored [-Wattributes]

> template <>
> void*
> ATTR ((hot)) ATTR ((alloc_size (1))) ATTR ((malloc))
> missing_all(int);   // T = char, same as above

# Comparing 8 common sum files
## /bin/sh contrib/compare_tests  /tmp/gxx-sum1.948624 /tmp/gxx-sum2.948624
Tests that now fail, but worked before (4 tests):

g++.dg/Wmissing-attributes.C  -std=gnu++14 (test for excess errors)
g++.dg/Wmissing-attributes.C  -std=gnu++17 (test for excess errors)
g++.dg/Wmissing-attributes.C  -std=gnu++20 (test for excess errors)
g++.dg/Wmissing-attributes.C  -std=gnu++98 (test for excess errors)

New tests that PASS (20 tests):

g++.dg/ext/attr-hotness.C  -std=gnu++14  (test for warnings, line 11)
g++.dg/ext/attr-hotness.C  -std=gnu++14  (test for warnings, line 9)
g++.dg/ext/attr-hotness.C  -std=gnu++14  scan-tree-dump-times gimple "cold"
2
g++.dg/ext/attr-hotness.C  -std=gnu++14  scan-tree-dump-times gimple "hot" 2
g++.dg/ext/attr-hotness.C  -std=gnu++14 (test for excess errors)
g++.dg/ext/attr-hotness.C  -std=gnu++17  (test for warnings, line 11)
g++.dg/ext/attr-hotness.C  -std=gnu++17  (test for warnings, line 9)
g++.dg/ext/attr-hotness.C  -std=gnu++17  scan-tree-dump-times gimple "cold"
2
g++.dg/ext/attr-hotness.C  -std=gnu++17  scan-tree-dump-times gimple "hot" 2
g++.dg/ext/attr-hotness.C  -std=gnu++17 (test for excess errors)
g++.dg/ext/attr-hotness.C  -std=gnu++20  (test for warnings, line 11)
g++.dg/ext/attr-hotness.C  -std=gnu++20  (test for warnings, line 9)
g++.dg/ext/attr-hotness.C  -std=gnu++20  scan-tree-dump-times gimple "cold"
2
g++.dg/ext/attr-hotness.C  -std=gnu++20  scan-tree-dump-times gimple "hot" 2
g++.dg/ext/attr-hotness.C  -std=gnu++20 (test for excess errors)
g++.dg/ext/attr-hotness.C  -std=gnu++98  (test for warnings, line 11)
g++.dg/ext/attr-hotness.C  -std=gnu++98  (test for warnings, line 9)
g++.dg/ext/attr-hotness.C  -std=gnu++98  scan-tree-dump-times gimple "cold"
2
g++.dg/ext/attr-hotness.C  -std=gnu++98  scan-tree-dump-times gimple "hot" 2
g++.dg/ext/attr-hotness.C  -std=gnu++98 (test for excess errors)

## Differences found:
# 1 differences in 8 common sum files found

---

gcc/c-family/ChangeLog:

* c-attribs.cc (handle_hot_attribute): remove warning on RECORD_TYPE
and UNION_TYPE when in c_dialect_xx.
(handle_cold_attribute): Likewise.

gcc/cp/ChangeLog:

* class.cc (propagate_class_warmth_attribute): New function.
(finish_struct): propagate hot and cold
attributes to all FUNCTION_DECL when the class is marked hot or
cold.

gcc/testsuite/ChangeLog:

* g++.dg/ext/attr-hotness.C: New test.

Signed-off-by: Javier Martinez 

---
 gcc/c-family/c-attribs.cc   | 26 --
 gcc/cp/class.cc | 47 +
 gcc/testsuite/g++.dg/ext/attr-hotness.C | 16 +
 3 files changed, 87 insertions(+), 2 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/ext/attr-hotness.C

diff --git a/gcc/c-family/c-attribs.cc b/gcc/c-fam

[RFC] c++: extend cold, hot attributes to classes

2023-08-03 Thread Javier Martinez via Gcc-patches
Most code is cold. This patch extends support for attribute ((cold)) to C++
Classes, Unions, and Structs (RECORD_TYPES and UNION_TYPES) to benefit from
encapsulation - reducing the verbosity of using the attribute where
deserved. The ((hot)) attribute is also extended for its semantic relation.
What is the sentiment on this use-case?

for gcc/c-family/ChangeLog

* c-attribs.c (attribute_spec): Remove decl_required
field for "hot" and "cold" attributes.
(handle_cold_attribute): remove warning on RECORD_TYPE
and UNION_TYPE when c_dialect_cxx.
(handle_cold_attribute): remove warning on RECORD_TYPE
and UNION_TYPE when c_dialect_cxx.

for gcc/cp/ChangeLog

* class.c (finish_struct) propagate hot and cold
attributes to all FUNCTION_DECL when the class
itself is marked hot or cold.

for  gcc/testsuite/ChangeLog

* g++.dg/ext/attr-hotness.C: New.


Signed-off-by: Javier Martinez 

diff --git a/gcc/c-family/c-attribs.c b/gcc/c-family/c-attribs.c
index dc9579c..815df66 100644
--- a/gcc/c-family/c-attribs.c
+++ b/gcc/c-family/c-attribs.c
@@ -398,10 +398,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",
@@ -837,22 +837,23 @@ handle_noreturn_attribute (tree *node, tree name,
tree ARG_UNUSED (args),

 static tree
 handle_hot_attribute (tree *node, tree name, tree ARG_UNUSED (args),
-  int ARG_UNUSED (flags), bool *no_add_attrs)
+   int ARG_UNUSED (flags), bool *no_add_attrs)
 {
-  if (TREE_CODE (*node) == FUNCTION_DECL
-  || TREE_CODE (*node) == LABEL_DECL)
+  if ( (TREE_CODE (*node) == FUNCTION_DECL ||
+TREE_CODE (*node) == LABEL_DECL)
+  || ((TREE_CODE(*node) == RECORD_TYPE ||
+   TREE_CODE(*node) == UNION_TYPE) && c_dialect_cxx()))
 {
   /* Attribute hot processing is done later with lookup_attribute.  */
 }
   else
 {
   warning (OPT_Wattributes, "%qE attribute ignored", name);
-  *no_add_attrs = true;
+  *no_add_attrs = true;
 }

   return NULL_TREE;
 }
-
 /* Handle a "cold" and attribute; arguments as in
struct attribute_spec.handler.  */

@@ -860,15 +861,17 @@ static tree
 handle_cold_attribute (tree *node, tree name, tree ARG_UNUSED (args),
int ARG_UNUSED (flags), bool *no_add_attrs)
 {
-  if (TREE_CODE (*node) == FUNCTION_DECL
-  || TREE_CODE (*node) == LABEL_DECL)
+  if ( (TREE_CODE (*node) == FUNCTION_DECL ||
+TREE_CODE (*node) == LABEL_DECL)
+  || ((TREE_CODE(*node) == RECORD_TYPE ||
+   TREE_CODE(*node) == UNION_TYPE) && c_dialect_cxx()))
 {
   /* Attribute cold processing is done later with lookup_attribute.  */
 }
   else
 {
   warning (OPT_Wattributes, "%qE attribute ignored", name);
-  *no_add_attrs = true;
+  *no_add_attrs = true;
 }

   return NULL_TREE;
diff --git a/gcc/cp/class.c b/gcc/cp/class.c
index 07abe52..70f734f 100644
--- a/gcc/cp/class.c
+++ b/gcc/cp/class.c
@@ -7540,6 +7540,35 @@ finish_struct (tree t, tree attributes)
   && !LAMBDA_TYPE_P (t))
 add_stmt (build_min (TAG_DEFN, t));

+
+  /* classes marked with hotness attributes propagate the attribute to
+  all methods. We propagate these here as there is a guarantee that
+  TYPE_FIELDS is populated, as opposed from within decl_attributes. */
+
+  tree has_cold_attr = lookup_attribute("cold", TYPE_ATTRIBUTES(t));
+  tree has_hot_attr = lookup_attribute("hot", TYPE_ATTRIBUTES(t));
+
+  if ( has_cold_attr || has_hot_attr ) {
+
+/* hoisted out of the loop */
+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) {
+  /* decl_attributes will take care of conflicts,
+  also prioritizing attributes explicitly marked in methods */
+
+  if (has_cold_attr) {
+decl_attributes (&f, tree_cons (attr_cold_id, NULL, NULL), 0);
+  } else if (has_hot_attr) {
+decl_attributes (&f, tree_cons (attr_hot_id, NULL, NULL), 0);
+  }
+}
+  }
+  }
+
   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 000..075c624
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/attr-hotness.C
@@ -0,0 +1,15 @@
+/* { dg-do compile } */
+/* { dg-options "-O0 -Wattributes -fdump-tree-gimple" }