[ping][PATCH] cp: warn uninitialized const/ref in base class [PR80681]

2023-01-04 Thread Charlie Sale via Gcc-patches
On this example:
```
struct Fine {
private:
const int f;
};

struct BuggyA {
const int a;
int &b;
};

struct BuggyB : private BuggyA {
};
```
g++ currently emits:
```
test.cc:3:19: warning: non-static const member ‘const int Fine::f’ in class 
without a constructor [-Wuninitialized]
3 | const int f;
  |
```
(relevant godbolt: https://godbolt.org/z/KGMK6e1zc)
The issue here is that g++ misses the uninitialized const and ref members in 
BuggyA that are inherited as
private in BuggyB. It should warn about those members when checking BuggyB.

With this patch, g++ emits the following:
```
test.cc:3:19: warning: non-static const member ‘const int Fine::f’ in class 
without a constructor [-Wuninitialized]
3 | const int f;
  |   ^
test.cc:7:19: warning: while processing ‘BuggyB’: non-static const member 
‘const int BuggyA::a’ in class without a constructor [-Wuninitialized]
7 | const int a;
  |   ^
test.cc:7:19: note: ‘BuggyB’ inherits ‘BuggyA’ as private, so all fields 
contained within ‘BuggyA’ are private to ‘BuggyB’
test.cc:8:14: warning: while processing ‘BuggyB’: non-static reference ‘int& 
BuggyA::b’ in class without a constructor [-Wuninitialized]
8 | int &b;
  |  ^
test.cc:8:14: note: ‘BuggyB’ inherits ‘BuggyA’ as private, so all fields 
contained within ‘BuggyA’ are private to ‘BuggyB’
```
Now, the compiler warns about the uninitialized members.

In terms of testing, I added three tests:
- a status quo test that makes sure that the existing warning behavior
  works
- A simple test based off of the PR
- Another example with multiple inheritance
- A final example with mutliple levels of inheritance.

These tests all pass. I also bootstrapped the project without any
regressions.

PR c++/80681

gcc/cp/ChangeLog:

* class.cc (warn_uninitialized_const_and_ref): Extract warn logic
  into new func, add inform for inheritance warning
(check_bases_and_members): Move warn logic to
  warn_unintialized_const_and_ref, check subclasses for warnings
  as well

gcc/testsuite/ChangeLog:

* g++.dg/pr80681-1.C: New test.

Signed-off-by: Charlie Sale 
---
 gcc/cp/class.cc  | 110 +--
 gcc/testsuite/g++.dg/pr80681-1.C |  51 ++
 2 files changed, 142 insertions(+), 19 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/pr80681-1.C

diff --git a/gcc/cp/class.cc b/gcc/cp/class.cc
index aebcb53739e..72172bea6ad 100644
--- a/gcc/cp/class.cc
+++ b/gcc/cp/class.cc
@@ -6018,6 +6018,76 @@ explain_non_literal_class (tree t)
 }
 }
 
+
+/* Warn for private const or reference class members that cannot be initialized
+   due to the class not having a default constructor.  If a child type is
+   provided, then we are checking class_type's members in case they cannot be
+   initialized by child_type.  If child_type is null, then we simply check
+   class_type.  */
+static void
+warn_uninitialized_const_and_ref (tree class_type, tree child_type)
+{
+  /* Check the fields on this class type.  */
+  tree field;
+  for (field = TYPE_FIELDS (class_type); field; field = DECL_CHAIN (field))
+{
+  /* We only want to check variable declarations.
+   Exclude fields that are not field decls or are not initialized.  */
+  if (TREE_CODE (field) != FIELD_DECL
+ || DECL_INITIAL (field) != NULL_TREE)
+   continue;
+
+  tree type = TREE_TYPE (field);
+
+  if (TYPE_REF_P (type))
+   {
+ if (child_type != nullptr)
+  {
+   /* Show parent class while processing.  */
+   auto_diagnostic_group d;
+   warning_at (DECL_SOURCE_LOCATION (field),
+   OPT_Wuninitialized, "while processing %qE: "
+   "non-static reference %q#D in class without a constructor",
+   child_type, field);
+   inform (DECL_SOURCE_LOCATION (field),
+   "%qE inherits %qE as private, so all fields "
+   "contained within %qE are private to %qE",
+   child_type, class_type, class_type, child_type);
+  }
+ else
+  {
+   warning_at (DECL_SOURCE_LOCATION (field),
+   OPT_Wuninitialized, "non-static reference %q#D "
+   "in class without a constructor", field);
+  }
+   }
+  else if (CP_TYPE_CONST_P (type)
+  && (!CLASS_TYPE_P (type)
+  || !TYPE_HAS_DEFAULT_CONSTRUCTOR (type)))
+   {
+ if (child_type)
+  {
+   /* ditto.  */
+   auto_diagnostic_group d;
+   warning_at (DECL_SOURCE_LOCATION (field),
+   OPT_Wuninitialized, "while processing %qE: "
+   "non-static const member %q#D in class "
+   "without a constructor", child_type, field);
+   inform (DECL_SOURCE_LOCATION (field),
+   "%qE inherits %qE as private, so all fields "

[PATCH] cp: warn uninitialized const/ref in base class [PR80681]

2022-12-24 Thread Charlie Sale via Gcc-patches
On this example:
```
struct Fine {
private:
const int f;
};

struct BuggyA {
const int a;
int &b;
};

struct BuggyB : private BuggyA {
};
```
g++ currently emits:
```
test.cc:3:19: warning: non-static const member ‘const int Fine::f’ in class 
without a constructor [-Wuninitialized]
3 | const int f;
  |
```
(relevant godbolt: https://godbolt.org/z/KGMK6e1zc)
The issue here is that g++ misses the uninitialized const and ref members in 
BuggyA that are inherited as
private in BuggyB. It should warn about those members when checking BuggyB.

With this patch, g++ emits the following:
```
test.cc:3:19: warning: non-static const member ‘const int Fine::f’ in class 
without a constructor [-Wuninitialized]
3 | const int f;
  |   ^
test.cc:7:19: warning: while processing ‘BuggyB’: non-static const member 
‘const int BuggyA::a’ in class without a constructor [-Wuninitialized]
7 | const int a;
  |   ^
test.cc:7:19: note: ‘BuggyB’ inherits ‘BuggyA’ as private, so all fields 
contained within ‘BuggyA’ are private to ‘BuggyB’
test.cc:8:14: warning: while processing ‘BuggyB’: non-static reference ‘int& 
BuggyA::b’ in class without a constructor [-Wuninitialized]
8 | int &b;
  |  ^
test.cc:8:14: note: ‘BuggyB’ inherits ‘BuggyA’ as private, so all fields 
contained within ‘BuggyA’ are private to ‘BuggyB’
```
Now, the compiler warns about the uninitialized members.

In terms of testing, I added three tests:
- a status quo test that makes sure that the existing warning behavior
  works
- A simple test based off of the PR
- Another example with multiple inheritance
- A final example with mutliple levels of inheritance.

These tests all pass. I also bootstrapped the project without any
regressions.

PR c++/80681

gcc/cp/ChangeLog:

* class.cc (warn_uninitialized_const_and_ref): Extract warn logic
  into new func, add inform for inheritance warning
(check_bases_and_members): Move warn logic to
  warn_unintialized_const_and_ref, check subclasses for warnings
  as well

gcc/testsuite/ChangeLog:

* g++.dg/pr80681-1.C: New test.

Signed-off-by: Charlie Sale 
---
 gcc/cp/class.cc  | 110 +--
 gcc/testsuite/g++.dg/pr80681-1.C |  51 ++
 2 files changed, 142 insertions(+), 19 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/pr80681-1.C

diff --git a/gcc/cp/class.cc b/gcc/cp/class.cc
index aebcb53739e..72172bea6ad 100644
--- a/gcc/cp/class.cc
+++ b/gcc/cp/class.cc
@@ -6018,6 +6018,76 @@ explain_non_literal_class (tree t)
 }
 }
 
+
+/* Warn for private const or reference class members that cannot be initialized
+   due to the class not having a default constructor.  If a child type is
+   provided, then we are checking class_type's members in case they cannot be
+   initialized by child_type.  If child_type is null, then we simply check
+   class_type.  */
+static void
+warn_uninitialized_const_and_ref (tree class_type, tree child_type)
+{
+  /* Check the fields on this class type.  */
+  tree field;
+  for (field = TYPE_FIELDS (class_type); field; field = DECL_CHAIN (field))
+{
+  /* We only want to check variable declarations.
+   Exclude fields that are not field decls or are not initialized.  */
+  if (TREE_CODE (field) != FIELD_DECL
+ || DECL_INITIAL (field) != NULL_TREE)
+   continue;
+
+  tree type = TREE_TYPE (field);
+
+  if (TYPE_REF_P (type))
+   {
+ if (child_type != nullptr)
+  {
+   /* Show parent class while processing.  */
+   auto_diagnostic_group d;
+   warning_at (DECL_SOURCE_LOCATION (field),
+   OPT_Wuninitialized, "while processing %qE: "
+   "non-static reference %q#D in class without a constructor",
+   child_type, field);
+   inform (DECL_SOURCE_LOCATION (field),
+   "%qE inherits %qE as private, so all fields "
+   "contained within %qE are private to %qE",
+   child_type, class_type, class_type, child_type);
+  }
+ else
+  {
+   warning_at (DECL_SOURCE_LOCATION (field),
+   OPT_Wuninitialized, "non-static reference %q#D "
+   "in class without a constructor", field);
+  }
+   }
+  else if (CP_TYPE_CONST_P (type)
+  && (!CLASS_TYPE_P (type)
+  || !TYPE_HAS_DEFAULT_CONSTRUCTOR (type)))
+   {
+ if (child_type)
+  {
+   /* ditto.  */
+   auto_diagnostic_group d;
+   warning_at (DECL_SOURCE_LOCATION (field),
+   OPT_Wuninitialized, "while processing %qE: "
+   "non-static const member %q#D in class "
+   "without a constructor", child_type, field);
+   inform (DECL_SOURCE_LOCATION (field),
+   "%qE inherits %qE as private, so all fields "

[PATCH] rtl: add predicates for addition, subtraction & multiplication

2022-11-26 Thread Charlie Sale via Gcc-patches
This is my first contribution to GCC :) one of the beginner projects
suggested on the website was to add and use RTL type predicates. I
added predicates for addition, subtraction and multiplication. I also
went through and used them in the code.

I did not add tests because I'm not addding/modifying any behavior.
All existings tests did pass.

Like I said, this is my first patch. Please let me know if I did
anything wrong or if there's anything I can improve for next time.

Signed-off-by: Charlie Sale 
---
 gcc/ChangeLog|  43 +++
 gcc/alias.cc |  30 +++--
 gcc/auto-inc-dec.cc  |  11 +-
 gcc/calls.cc |   8 +-
 gcc/cfgexpand.cc |  16 +--
 gcc/combine-stack-adj.cc |  39 +++
 gcc/combine.cc   | 241 +--
 gcc/compare-elim.cc  |   3 +-
 gcc/cse.cc   |  66 +--
 gcc/cselib.cc|  37 +++---
 gcc/dce.cc   |   4 +-
 gcc/dwarf2cfi.cc |   2 +-
 gcc/dwarf2out.cc |  11 +-
 gcc/emit-rtl.cc  |   6 +-
 gcc/explow.cc|  31 ++---
 gcc/expr.cc  |  23 ++--
 gcc/final.cc |  20 ++--
 gcc/function.cc  |   7 +-
 gcc/fwprop.cc|   2 +-
 gcc/haifa-sched.cc   |  10 +-
 gcc/ifcvt.cc |  11 +-
 gcc/ira.cc   |   6 +-
 gcc/loop-doloop.cc   |  70 ++--
 gcc/loop-iv.cc   |  21 +---
 gcc/lra-constraints.cc   |  34 +++---
 gcc/lra-eliminations.cc  |  25 ++--
 gcc/lra.cc   |   6 +-
 gcc/modulo-sched.cc  |   2 +-
 gcc/postreload.cc|  25 ++--
 gcc/reginfo.cc   |  12 +-
 gcc/reload.cc| 180 +
 gcc/reload1.cc   |  85 ++
 gcc/reorg.cc |  12 +-
 gcc/rtl.cc   |   3 +-
 gcc/rtl.h|  11 ++
 gcc/rtlanal.cc   |  25 ++--
 gcc/sched-deps.cc|   8 +-
 gcc/simplify-rtx.cc  | 143 +--
 gcc/var-tracking.cc  |  37 +++---
 39 files changed, 595 insertions(+), 731 deletions(-)

diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index f999e2cba43..1fd2c94c873 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,46 @@
+2022-11-26  Charlie Sale   
+
+   * rtl.h (PLUS_P): RTL addition predicate
+   (MINUS_P): RTL subtraction predicate
+   (MULT_P): RTL multiplication predicate
+   * alias.cc: use RTL predicates
+   * auto-inc-dec.cc: use RTL predicates
+   * calls.cc: use RTL predicates
+   * cfgexpand.cc: use RTL predicates
+   * combine-stack-adj.cc: use RTL predicates
+   * combine.cc: use RTL predicates
+   * compare-elim.cc: use RTL predicates
+   * cse.cc: use RTL predicates
+   * cselib.cc: use RTL predicates
+   * dce.cc: use RTL predicates
+   * dwarf2cfi.cc: use RTL predicates
+   * dwarf2out.cc: use RTL predicates
+   * emit-rtl.cc: use RTL predicates
+   * explow.cc: use RTL predicates
+   * expr.cc: use RTL predicates
+   * final.cc: use RTL predicates
+   * function.cc: use RTL predicates
+   * fwprop.cc: use RTL predicates
+   * haifa-sched.cc: use RTL predicates
+   * ifcvt.cc: use RTL predicates
+   * ira.cc: use RTL predicates
+   * loop-doloop.cc: use RTL predicates
+   * loop-iv.cc: use RTL predicates
+   * lra-constraints.cc: use RTL predicates
+   * lra-eliminations.cc: use RTL predicates
+   * lra.cc: use RTL predicates
+   * modulo-sched.cc: use RTL predicates
+   * postreload.cc: use RTL predicates
+   * reginfo.cc: use RTL predicates
+   * reload.cc: use RTL predicates
+   * reload1.cc: use RTL predicates
+   * reorg.cc: use RTL predicates
+   * rtl.cc: use RTL predicates
+   * rtlanal.cc: use RTL predicates
+   * sched-deps.cc: use RTL predicates
+   * simplify-rtx.cc: use RTL predicates
+   * var-tracking.cc: use RTL predicates
+
 2022-11-25  Sandra Loosemore  
 
* common.opt (fopenmp-target-simd-clone): New option.
diff --git a/gcc/alias.cc b/gcc/alias.cc
index c62837dd854..2d9bd79fe21 100644
--- a/gcc/alias.cc
+++ b/gcc/alias.cc
@@ -1473,7 +1473,7 @@ find_base_value (rtx src)
 otherwise.  */
   if (copying_arguments
  && (XEXP (src, 0) == arg_pointer_rtx
- || (GET_CODE (XEXP (src, 0)) == PLUS
+ || (PLUS_P (XEXP (src, 0))
  && XEXP (XEXP (src, 0), 0) == arg_pointer_rtx)))
return arg_base_value;
   return 0;
@@ -1790,7 +1790,7 @@ canon_rtx (rtx x)
return canon_rtx (t);
 }
 
-  if (GET_CODE (x) == PLUS)
+  if (PLUS_P (x))
 {
   rtx x0 = canon_rtx (XEXP (x, 0));
   rtx x1 = canon_rtx (XEXP (x, 1));
@@ -2357,19 +2357,17 @@ get_addr (rtx x)
 
   if (GET_CODE (x) != VALUE)
 {
-  if ((GET_CODE (x) == PLUS || GET_CODE (x) == MINUS)
- && GET_CODE (XEXP (x, 0)) == VALUE
+  if ((PLUS_P (x) || MINUS_P (x)) && GET_CODE (XEXP (x, 0)) == VALUE