From: Marek Polacek Date: Wed, 10 Jun 2026 20:43:18 +0000 (-0400) Subject: c++: fix spurious -Wrange-loop-construct warning [PR125697] X-Git-Url: http://git.ipfire.org/index.cgi?a=commitdiff_plain;p=thirdparty%2Fgcc.git 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` which makes it seem like `pair::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 &` 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 --- diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 6df271d5e35..132139f9d52 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 38b5bd3e1ce..1ce591666fe 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 f15be65c246..bf1c41772d3 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 a99f5e19c0d..d9a0583b8b8 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 76fae1da0bb..06399e3b903 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 00000000000..2d792786e0b --- /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 struct pair { + int first; + int second; + template pair(const pair<_U1> &&); +}; +void +foo (const pair (&arr)[1]) +{ + for (const auto x : arr) // { dg-bogus "creates a copy" } + (void) x; +} +static_assert(__is_trivially_copyable(pair)); +static_assert(!__is_trivially_constructible(pair)); + +template struct pairbig { + int first; + int second; + char arr[64]; + template pairbig(const pairbig<_U1> &&); +}; +void +bar (const pairbig (&arr)[1]) +{ + for (const auto x : arr) // { dg-warning "creates a copy" } + (void) x; +} +static_assert(__is_trivially_copyable(pairbig)); +static_assert(!__is_trivially_constructible(pairbig)); + +template struct pairnontriv { + int first; + int second; + pairnontriv(const pairnontriv &); + template pairnontriv(const pairnontriv<_U1> &&); +}; +void +baz (const pairnontriv (&arr)[1]) +{ + for (const auto x : arr) // { dg-warning "creates a copy" } + (void) x; +} +static_assert(!__is_trivially_copyable(pairnontriv)); +static_assert(!__is_trivially_constructible(pairnontriv));