https://gcc.gnu.org/g:49ba5321b3586c076728ad34ed7030c5a472c892

commit r17-1757-g49ba5321b3586c076728ad34ed7030c5a472c892
Author: Marek Polacek <[email protected]>
Date:   Wed Jun 10 16:43:18 2026 -0400

    c++: fix spurious -Wrange-loop-construct warning [PR125697]
    
    Here we issue a bogus -Wrange-loop-construct warning because the
    is_trivially_xible check uses `const pair<int>` which makes it seem
    like `pair<T>::pair(const pair<_U1> &&)` would actually be used,
    which is non-trivial, while the loop would actually use a trivial
    copy.  Fixed by using `const pair<int> &` for the is_trivially_xible
    check.
    
            PR c++/125697
    
    gcc/cp/ChangeLog:
    
            * cp-tree.h (trivially_copy_constructible_p): Declare.
            * parser.cc (warn_for_range_copy): Use it.
            * reflect.cc (eval_is_trivially_copy_constructible_type): Use it.
            * tree.cc (trivially_copy_constructible_p): New.
    
    gcc/ChangeLog:
    
            * doc/invoke.texi: Clarify -Wrange-loop-construct description.
    
    gcc/testsuite/ChangeLog:
    
            * g++.dg/warn/Wrange-loop-construct4.C: New test.
    
    Reviewed-by: Jason Merrill <[email protected]>

Diff:
---
 gcc/cp/cp-tree.h                                   |  1 +
 gcc/cp/parser.cc                                   |  4 +-
 gcc/cp/reflect.cc                                  |  5 +--
 gcc/cp/tree.cc                                     | 11 +++++
 gcc/doc/invoke.texi                                |  4 +-
 gcc/testsuite/g++.dg/warn/Wrange-loop-construct4.C | 47 ++++++++++++++++++++++
 6 files changed, 63 insertions(+), 9 deletions(-)

diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 6df271d5e359..132139f9d520 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -8749,6 +8749,7 @@ extern bool std_layout_type_p                     
(const_tree);
 extern bool trivial_type_p                     (const_tree);
 extern bool implicit_lifetime_type_p           (tree);
 extern bool trivially_copyable_p               (const_tree);
+extern bool trivially_copy_constructible_p     (tree);
 extern bool has_trivial_abi_attribute          (tree);
 extern void validate_trivial_abi_attribute     (tree);
 extern bool type_has_unique_obj_representations (const_tree, bool = false);
diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
index 38b5bd3e1ce4..1ce591666fe3 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -16015,11 +16015,9 @@ warn_for_range_copy (tree decl, tree expr)
 
   /* Since small trivially constructible types are cheap to construct, we
      suppress the warning for them.  64B is a common size of a cache line.  */
-  tree vec = make_tree_vec (1);
-  TREE_VEC_ELT (vec, 0) = TREE_TYPE (expr);
   if (TREE_CODE (TYPE_SIZE_UNIT (type)) != INTEGER_CST
       || (tree_to_uhwi (TYPE_SIZE_UNIT (type)) <= 64
-         && is_trivially_xible (INIT_EXPR, type, vec)))
+         && trivially_copy_constructible_p (type)))
     return;
 
   /* If we can initialize a reference directly, suggest that to avoid the
diff --git a/gcc/cp/reflect.cc b/gcc/cp/reflect.cc
index f15be65c2466..bf1c41772d34 100644
--- a/gcc/cp/reflect.cc
+++ b/gcc/cp/reflect.cc
@@ -4661,10 +4661,7 @@ eval_is_trivially_default_constructible_type (tree type)
 static tree
 eval_is_trivially_copy_constructible_type (tree type)
 {
-  tree arg = make_tree_vec (1);
-  TREE_VEC_ELT (arg, 0)
-    = build_stub_type (type, cp_type_quals (type) | TYPE_QUAL_CONST, false);
-  if (is_trivially_xible (INIT_EXPR, type, arg))
+  if (trivially_copy_constructible_p (type))
     return boolean_true_node;
   else
     return boolean_false_node;
diff --git a/gcc/cp/tree.cc b/gcc/cp/tree.cc
index a99f5e19c0d8..d9a0583b8b83 100644
--- a/gcc/cp/tree.cc
+++ b/gcc/cp/tree.cc
@@ -4909,6 +4909,17 @@ trivial_type_p (const_tree t)
     return scalarish_type_p (t);
 }
 
+/* Returns true iff type T is a trivially copy constructible type.  */
+
+bool
+trivially_copy_constructible_p (tree t)
+{
+  tree arg = make_tree_vec (1);
+  TREE_VEC_ELT (arg, 0)
+    = build_stub_type (t, cp_type_quals (t) | TYPE_QUAL_CONST, false);
+  return is_trivially_xible (INIT_EXPR, t, arg);
+}
+
 /* Returns 1 iff type T is an implicit-lifetime type, as defined in
    [basic.types.general] and [class.prop].  */
 
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 76fae1da0bb3..06399e3b903c 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -4517,8 +4517,8 @@ void fn () @{
 @}
 @end smallexample
 
-It does not warn when the type being copied is a trivially-copyable type whose
-size is less than 64 bytes.
+It does not warn when the type being copied is a trivially copy constructible
+type whose size is less than 64 bytes.
 
 This warning also warns when a loop variable in a range-based for-loop is
 initialized with a value of a different type resulting in a copy.  For example:
diff --git a/gcc/testsuite/g++.dg/warn/Wrange-loop-construct4.C 
b/gcc/testsuite/g++.dg/warn/Wrange-loop-construct4.C
new file mode 100644
index 000000000000..2d792786e0bc
--- /dev/null
+++ b/gcc/testsuite/g++.dg/warn/Wrange-loop-construct4.C
@@ -0,0 +1,47 @@
+// PR c++/125697
+// { dg-do compile { target c++11 } }
+// { dg-options "-Wrange-loop-construct" }
+
+template <typename> struct pair {
+  int first;
+  int second;
+  template <typename _U1> pair(const pair<_U1> &&);
+};
+void
+foo (const pair<int> (&arr)[1])
+{
+  for (const auto x : arr)  // { dg-bogus "creates a copy" }
+    (void) x;
+}
+static_assert(__is_trivially_copyable(pair<int>));
+static_assert(!__is_trivially_constructible(pair<int>));
+
+template <typename> struct pairbig {
+  int first;
+  int second;
+  char arr[64];
+  template <typename _U1> pairbig(const pairbig<_U1> &&);
+};
+void
+bar (const pairbig<int> (&arr)[1])
+{
+  for (const auto x : arr)  // { dg-warning "creates a copy" }
+    (void) x;
+}
+static_assert(__is_trivially_copyable(pairbig<int>));
+static_assert(!__is_trivially_constructible(pairbig<int>));
+
+template <typename> struct pairnontriv {
+  int first;
+  int second;
+  pairnontriv(const pairnontriv &);
+  template <typename _U1> pairnontriv(const pairnontriv<_U1> &&);
+};
+void
+baz (const pairnontriv<int> (&arr)[1])
+{
+  for (const auto x : arr)  // { dg-warning "creates a copy" }
+    (void) x;
+}
+static_assert(!__is_trivially_copyable(pairnontriv<int>));
+static_assert(!__is_trivially_constructible(pairnontriv<int>));

Reply via email to