aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/c-family/c.opt5
-rw-r--r--gcc/cp/pt.c28
-rw-r--r--gcc/doc/invoke.texi22
-rw-r--r--gcc/testsuite/g++.dg/warn/Wctad-maybe-unsupported.C88
-rw-r--r--gcc/testsuite/g++.dg/warn/Wctad-maybe-unsupported.h4
-rw-r--r--gcc/testsuite/g++.dg/warn/Wctad-maybe-unsupported2.C6
-rw-r--r--gcc/testsuite/g++.dg/warn/Wctad-maybe-unsupported3.C6
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" }