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>));
