r351484 - Add -Wctad-maybe-unsupported to diagnose CTAD on types with no user defined deduction guides.
Eric Fiselier via cfe-commits
cfe-commits at lists.llvm.org
Thu Jan 17 13:44:24 PST 2019
Author: ericwf
Date: Thu Jan 17 13:44:24 2019
New Revision: 351484
URL: http://llvm.org/viewvc/llvm-project?rev=351484&view=rev
Log:
Add -Wctad-maybe-unsupported to diagnose CTAD on types with no user defined deduction guides.
Summary:
Some style guides want to allow using CTAD only on types that "opt-in"; i.e. on types that are designed to support it and not just types that *happen* to work with it.
This patch implements the `-Wctad-maybe-unsupported` warning, which is off by default, which warns when CTAD is used on a type that does not define any deduction guides.
The following pattern can be used to suppress the warning in cases where the type intentionally doesn't define any deduction guides:
```
struct allow_ctad_t;
template <class T>
struct TestSuppression {
TestSuppression(T) {}
};
TestSuppression(allow_ctad_t)->TestSuppression<void>; // guides with incomplete parameter types are never considered.
```
Reviewers: rsmith, james.dennett, gromer
Reviewed By: rsmith
Subscribers: jdennett, Quuxplusone, lebedev.ri, cfe-commits
Differential Revision: https://reviews.llvm.org/D56731
Modified:
cfe/trunk/include/clang/Basic/DiagnosticGroups.td
cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
cfe/trunk/lib/Sema/SemaInit.cpp
cfe/trunk/test/SemaCXX/cxx1z-class-template-argument-deduction.cpp
Modified: cfe/trunk/include/clang/Basic/DiagnosticGroups.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticGroups.td?rev=351484&r1=351483&r2=351484&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticGroups.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticGroups.td Thu Jan 17 13:44:24 2019
@@ -1050,3 +1050,5 @@ def NoDeref : DiagGroup<"noderef">;
// A group for cross translation unit static analysis related warnings.
def CrossTU : DiagGroup<"ctu">;
+
+def CTADMaybeUnsupported : DiagGroup<"ctad-maybe-unsupported">;
Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=351484&r1=351483&r2=351484&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Thu Jan 17 13:44:24 2019
@@ -2129,6 +2129,12 @@ def warn_cxx14_compat_class_template_arg
"class template argument deduction is incompatible with C++ standards "
"before C++17%select{|; for compatibility, use explicit type name %1}0">,
InGroup<CXXPre17Compat>, DefaultIgnore;
+def warn_ctad_maybe_unsupported : Warning<
+ "%0 may not intend to support class template argument deduction">,
+ InGroup<CTADMaybeUnsupported>, DefaultIgnore;
+def note_suppress_ctad_maybe_unsupported : Note<
+ "add a deduction guide to suppress this warning">;
+
// C++14 deduced return types
def err_auto_fn_deduction_failure : Error<
Modified: cfe/trunk/lib/Sema/SemaInit.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaInit.cpp?rev=351484&r1=351483&r2=351484&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaInit.cpp (original)
+++ cfe/trunk/lib/Sema/SemaInit.cpp Thu Jan 17 13:44:24 2019
@@ -9264,9 +9264,14 @@ QualType Sema::DeduceTemplateSpecializat
OverloadCandidateSet Candidates(Kind.getLocation(),
OverloadCandidateSet::CSK_Normal);
OverloadCandidateSet::iterator Best;
+
+ bool HasAnyDeductionGuide = false;
+
auto tryToResolveOverload =
[&](bool OnlyListConstructors) -> OverloadingResult {
Candidates.clear(OverloadCandidateSet::CSK_Normal);
+ HasAnyDeductionGuide = false;
+
for (auto I = Guides.begin(), E = Guides.end(); I != E; ++I) {
NamedDecl *D = (*I)->getUnderlyingDecl();
if (D->isInvalidDecl())
@@ -9278,6 +9283,9 @@ QualType Sema::DeduceTemplateSpecializat
if (!GD)
continue;
+ if (!GD->isImplicit())
+ HasAnyDeductionGuide = true;
+
// C++ [over.match.ctor]p1: (non-list copy-initialization from non-class)
// For copy-initialization, the candidate functions are all the
// converting constructors (12.3.1) of that class.
@@ -9430,5 +9438,15 @@ QualType Sema::DeduceTemplateSpecializat
Diag(TSInfo->getTypeLoc().getBeginLoc(),
diag::warn_cxx14_compat_class_template_argument_deduction)
<< TSInfo->getTypeLoc().getSourceRange() << 1 << DeducedType;
+
+ // Warn if CTAD was used on a type that does not have any user-defined
+ // deduction guides.
+ if (!HasAnyDeductionGuide) {
+ Diag(TSInfo->getTypeLoc().getBeginLoc(),
+ diag::warn_ctad_maybe_unsupported)
+ << TemplateName;
+ Diag(Template->getLocation(), diag::note_suppress_ctad_maybe_unsupported);
+ }
+
return DeducedType;
}
Modified: cfe/trunk/test/SemaCXX/cxx1z-class-template-argument-deduction.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/cxx1z-class-template-argument-deduction.cpp?rev=351484&r1=351483&r2=351484&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/cxx1z-class-template-argument-deduction.cpp (original)
+++ cfe/trunk/test/SemaCXX/cxx1z-class-template-argument-deduction.cpp Thu Jan 17 13:44:24 2019
@@ -409,6 +409,86 @@ B b(0, {});
}
+#pragma clang diagnostic push
+#pragma clang diagnostic warning "-Wctad-maybe-unsupported"
+namespace test_implicit_ctad_warning {
+
+template <class T>
+struct Tag {};
+
+template <class T>
+struct NoExplicit { // expected-note {{add a deduction guide to suppress this warning}}
+ NoExplicit(T) {}
+ NoExplicit(T, int) {}
+};
+
+// expected-warning at +1 {{'NoExplicit' may not intend to support class template argument deduction}}
+NoExplicit ne(42);
+
+template <class U>
+struct HasExplicit {
+ HasExplicit(U) {}
+ HasExplicit(U, int) {}
+};
+template <class U> HasExplicit(U, int) -> HasExplicit<Tag<U>>;
+
+HasExplicit he(42);
+
+// Motivating examples from (taken from Stephan Lavavej's 2018 Cppcon talk)
+template <class T, class U>
+struct AmateurPair { // expected-note {{add a deduction guide to suppress this warning}}
+ T first;
+ U second;
+ explicit AmateurPair(const T &t, const U &u) {}
+};
+// expected-warning at +1 {{'AmateurPair' may not intend to support class template argument deduction}}
+AmateurPair p1(42, "hello world"); // deduces to Pair<int, char[12]>
+
+template <class T, class U>
+struct AmateurPair2 { // expected-note {{add a deduction guide to suppress this warning}}
+ T first;
+ U second;
+ explicit AmateurPair2(T t, U u) {}
+};
+// expected-warning at +1 {{'AmateurPair2' may not intend to support class template argument deduction}}
+AmateurPair2 p2(42, "hello world"); // deduces to Pair2<int, const char*>
+
+template <class T, class U>
+struct ProPair {
+ T first; U second;
+ explicit ProPair(T const& t, U const& u) {}
+};
+template<class T1, class T2>
+ProPair(T1, T2) -> ProPair<T1, T2>;
+ProPair p3(42, "hello world"); // deduces to ProPair<int, const char*>
+static_assert(__is_same(decltype(p3), ProPair<int, const char*>));
+
+// Test that user-defined explicit guides suppress the warning even if they
+// aren't used as candidates.
+template <class T>
+struct TestExplicitCtor {
+ TestExplicitCtor(T) {}
+};
+template <class T>
+explicit TestExplicitCtor(TestExplicitCtor<T> const&) -> TestExplicitCtor<void>;
+TestExplicitCtor<int> ce1{42};
+TestExplicitCtor ce2 = ce1;
+static_assert(__is_same(decltype(ce2), TestExplicitCtor<int>), "");
+
+struct allow_ctad_t {
+ allow_ctad_t() = delete;
+};
+
+template <class T>
+struct TestSuppression {
+ TestSuppression(T) {}
+};
+TestSuppression(allow_ctad_t)->TestSuppression<void>;
+TestSuppression ta("abc");
+static_assert(__is_same(decltype(ta), TestSuppression<const char *>), "");
+}
+#pragma clang diagnostic pop
+
#else
// expected-no-diagnostics
More information about the cfe-commits
mailing list