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@+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@+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@+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 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits