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.
/* 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
{
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
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;
"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));
}
-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
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
--- /dev/null
+// 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 *>));
--- /dev/null
+#pragma GCC system_header
+
+template <typename T>
+struct A { A(T); };
--- /dev/null
+// { 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" }
--- /dev/null
+// { 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" }