diff options
-rw-r--r-- | gcc/c-family/c.opt | 5 | ||||
-rw-r--r-- | gcc/cp/pt.c | 28 | ||||
-rw-r--r-- | gcc/doc/invoke.texi | 22 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/warn/Wctad-maybe-unsupported.C | 88 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/warn/Wctad-maybe-unsupported.h | 4 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/warn/Wctad-maybe-unsupported2.C | 6 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/warn/Wctad-maybe-unsupported3.C | 6 |
7 files changed, 154 insertions, 5 deletions
diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt index 7a61351..da6c3e1 100644 --- a/gcc/c-family/c.opt +++ b/gcc/c-family/c.opt @@ -475,6 +475,11 @@ Wcpp C ObjC C++ ObjC++ CppReason(CPP_W_WARNING_DIRECTIVE) ; Documented in common.opt +Wctad-maybe-unsupported +C++ ObjC++ Var(warn_ctad_maybe_unsupported) Warning +Warn when performing class template argument deduction on a type with no +deduction guides. + Wctor-dtor-privacy C++ ObjC++ Var(warn_ctor_dtor_privacy) Warning Warn when all constructors and destructors are private. diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index fe45de8..97d0c24 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -28830,17 +28830,19 @@ static GTY((deletable)) hash_map<tree, tree_pair_p> *dguide_cache; /* Return the non-aggregate deduction guides for deducible template TMPL. The aggregate candidate is added separately because it depends on the - initializer. */ + initializer. Set ANY_DGUIDES_P if we find a non-implicit deduction + guide. */ static tree -deduction_guides_for (tree tmpl, tsubst_flags_t complain) +deduction_guides_for (tree tmpl, bool &any_dguides_p, tsubst_flags_t complain) { tree guides = NULL_TREE; if (DECL_ALIAS_TEMPLATE_P (tmpl)) { tree under = DECL_ORIGINAL_TYPE (DECL_TEMPLATE_RESULT (tmpl)); tree tinfo = get_template_info (under); - guides = deduction_guides_for (TI_TEMPLATE (tinfo), complain); + guides = deduction_guides_for (TI_TEMPLATE (tinfo), any_dguides_p, + complain); } else { @@ -28849,6 +28851,8 @@ deduction_guides_for (tree tmpl, tsubst_flags_t complain) LOOK_want::NORMAL, /*complain*/false); if (guides == error_mark_node) guides = NULL_TREE; + else + any_dguides_p = true; } /* Cache the deduction guides for a template. We also remember the result of @@ -28974,7 +28978,8 @@ do_class_deduction (tree ptype, tree tmpl, tree init, if (args == NULL) return error_mark_node; - tree cands = deduction_guides_for (tmpl, complain); + bool any_dguides_p = false; + tree cands = deduction_guides_for (tmpl, any_dguides_p, complain); if (cands == error_mark_node) return error_mark_node; @@ -29063,6 +29068,21 @@ do_class_deduction (tree ptype, tree tmpl, tree init, "for copy-initialization"); } + /* If CTAD succeeded but the type doesn't have any explicit deduction + guides, this deduction might not be what the user intended. */ + if (call != error_mark_node && !any_dguides_p) + { + tree fndecl = cp_get_callee_fndecl_nofold (call); + if (fndecl != NULL_TREE + && (!DECL_IN_SYSTEM_HEADER (fndecl) + || global_dc->dc_warn_system_headers) + && warning (OPT_Wctad_maybe_unsupported, + "%qT may not intend to support class template argument " + "deduction", type)) + inform (input_location, "add a deduction guide to suppress this " + "warning"); + } + return cp_build_qualified_type (TREE_TYPE (call), cp_type_quals (ptype)); } diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index 8be2b4f..665c0ff 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -236,7 +236,8 @@ in the following sections. -Wabi-tag -Wcatch-value -Wcatch-value=@var{n} @gol -Wno-class-conversion -Wclass-memaccess @gol -Wcomma-subscript -Wconditionally-supported @gol --Wno-conversion-null -Wctor-dtor-privacy -Wno-delete-incomplete @gol +-Wno-conversion-null -Wctad-maybe-unsupported @gol +-Wctor-dtor-privacy -Wno-delete-incomplete @gol -Wdelete-non-virtual-dtor -Wdeprecated-copy -Wdeprecated-copy-dtor @gol -Weffc++ -Wextra-semi -Wno-inaccessible-base @gol -Wno-inherited-variadic-ctor -Wno-init-list-lifetime @gol @@ -3304,6 +3305,25 @@ void f(int *a, int b, int c) @{ Enabled by default with @option{-std=c++20}. +@item -Wctad-maybe-unsupported @r{(C++ and Objective-C++ only)} +@opindex Wctad-maybe-unsupported +@opindex Wno-ctad-maybe-unsupported +Warn when performing class template argument deduction (CTAD) on a type with +no explicitly written deduction guides. This warning will point out cases +where CTAD succeeded only because the compiler synthesized the implicit +deduction guides, which might not be what the programmer intended. Certain +style guides allow CTAD only on types that specifically "opt-in"; i.e., on +types that are designed to support CTAD. This warning can be suppressed with +the following pattern: + +@smallexample +struct allow_ctad_t; // any name works +template <typename T> struct S @{ + S(T) @{ @} +@}; +S(allow_ctad_t) -> S<void>; // guide with incomplete parameter type will never be considered +@end smallexample + @item -Wctor-dtor-privacy @r{(C++ and Objective-C++ only)} @opindex Wctor-dtor-privacy @opindex Wno-ctor-dtor-privacy diff --git a/gcc/testsuite/g++.dg/warn/Wctad-maybe-unsupported.C b/gcc/testsuite/g++.dg/warn/Wctad-maybe-unsupported.C new file mode 100644 index 0000000..903e6f1 --- /dev/null +++ b/gcc/testsuite/g++.dg/warn/Wctad-maybe-unsupported.C @@ -0,0 +1,88 @@ +// Test -Wctad-maybe-unsupported. +// { dg-do compile { target c++17 } } +// { dg-options "-Wctad-maybe-unsupported" } + +template <typename T> struct Empty { }; + +template <typename T> +struct A { + A(T); // generates 'template<class T> A(T)-> A<T>' + A(T, int); // generates 'template<class T> A(T, int)-> A<T>' +}; + +// These only succeed because of the implicit guide. That may be +// undesired. +A a1(42); // { dg-warning "may not intend to support class template argument deduction" } +A a2{42}; // { dg-warning "may not intend to support class template argument deduction" } +A a3 = {42}; // { dg-warning "may not intend to support class template argument deduction" } + +template <typename T> +struct B { + B(T); + B(T, int); +}; +template <typename T> B(T, int) -> B<Empty<T>>; + +B b1(42); +B b2{42}; +B b3 = {42}; + +// Motivating examples from Stephan Lavavej's 2018 CppCon talk. +template <class T, class U> +struct Pair { + T first; + U second; + explicit Pair(const T &t, const U &u) {} +}; +// deduces to Pair<int, char[12]> +Pair p1(42, "hello world"); // { dg-warning "may not intend to support class template argument deduction" } +Pair p1b{42, "hello world"}; // { dg-warning "may not intend to support class template argument deduction" } + +template <class T, class U> +struct Pair2 { + T first; + U second; + explicit Pair2(T t, U u) {} +}; +// deduces to Pair2<int, const char*> +Pair2 p2(42, "hello world"); // { dg-warning "may not intend to support class template argument deduction" } +Pair2 p2b{42, "hello world"}; // { dg-warning "may not intend to support class template argument deduction" } + +template <class T, class U> +struct Pair3 { + T first; + U second; + explicit Pair3(T const& t, U const& u) {} +}; +template<class T1, class T2> +Pair3(T1, T2) -> Pair3<T1, T2>; + // deduces to Pair3<int, const char*> +Pair3 p3(42, "hello world"); +static_assert(__is_same(decltype(p3), Pair3<int, const char*>)); + +// Test that explicit guides suppress the warning even if they +// aren't used as candidates. +template <typename T> +struct C { + C(T) { } +}; +template <typename T> +explicit C(C<T> const&) -> C<void>; +C<int> c{42}; +C c2 = c; +static_assert(__is_same(decltype(c2), C<int>)); + +// Clang's suppression test. +struct allow_ctad_t { + allow_ctad_t() = delete; +}; + +template <typename T> +struct S { + S(T) {} +}; +S(allow_ctad_t) -> S<void>; +S s("abc"); +S s2{"abc"}; +static_assert(__is_same(decltype(s), S<const char *>)); +static_assert(__is_same(decltype(s2), S<const char *>)); diff --git a/gcc/testsuite/g++.dg/warn/Wctad-maybe-unsupported.h b/gcc/testsuite/g++.dg/warn/Wctad-maybe-unsupported.h new file mode 100644 index 0000000..9bb3154 --- /dev/null +++ b/gcc/testsuite/g++.dg/warn/Wctad-maybe-unsupported.h @@ -0,0 +1,4 @@ +#pragma GCC system_header + +template <typename T> +struct A { A(T); }; diff --git a/gcc/testsuite/g++.dg/warn/Wctad-maybe-unsupported2.C b/gcc/testsuite/g++.dg/warn/Wctad-maybe-unsupported2.C new file mode 100644 index 0000000..ce664bd --- /dev/null +++ b/gcc/testsuite/g++.dg/warn/Wctad-maybe-unsupported2.C @@ -0,0 +1,6 @@ +// { dg-do compile { target c++17 } } +// { dg-options "-Wctad-maybe-unsupported" } + +#include "Wctad-maybe-unsupported.h" + +A a{42}; // { dg-bogus "may not intend to support class template argument deduction" } diff --git a/gcc/testsuite/g++.dg/warn/Wctad-maybe-unsupported3.C b/gcc/testsuite/g++.dg/warn/Wctad-maybe-unsupported3.C new file mode 100644 index 0000000..c0ae633 --- /dev/null +++ b/gcc/testsuite/g++.dg/warn/Wctad-maybe-unsupported3.C @@ -0,0 +1,6 @@ +// { dg-do compile { target c++17 } } +// { dg-options "-Wctad-maybe-unsupported -Wsystem-headers" } + +#include "Wctad-maybe-unsupported.h" + +A a{42}; // { dg-warning "may not intend to support class template argument deduction" } |