Quuxplusone updated this revision to Diff 371350. Quuxplusone retitled this revision from "[clang] Enable the special enable_if_t diagnostics for libc++'s _EnableIf as well." to "[clang] Enable the special enable_if_t diagnostics for libc++'s __enable_if_t as well.". Quuxplusone edited the summary of this revision. Quuxplusone added a comment.
Okay, I think I've got it all sorted out in my head. This path forward seems reasonable to me: > D109435 <https://reviews.llvm.org/D109435> switches us from SCARY `_EnableIf` > to a normal `__enable_if_t` (at least in C++11 mode, and possibly everywhere > for consistency). Simultaneously, this Clang patch enables the good > diagnostics for `__enable_if_t`. We don't need to enable good diagnostics for > `_EnableIf` because the name `_EnableIf` has only ever been used for the > SCARY version where the good diagnostics don't trigger anyway. Added a test case. Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D109411/new/ https://reviews.llvm.org/D109411 Files: clang/lib/Sema/SemaTemplate.cpp clang/test/SemaTemplate/diagnose-enable-if-t.cpp
Index: clang/test/SemaTemplate/diagnose-enable-if-t.cpp =================================================================== --- /dev/null +++ clang/test/SemaTemplate/diagnose-enable-if-t.cpp @@ -0,0 +1,96 @@ +// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s +// RUN: %clang_cc1 -fsyntax-only -verify -std=c++14 %s +// RUN: %clang_cc1 -fsyntax-only -verify -std=c++17 %s +// RUN: %clang_cc1 -fsyntax-only -verify -std=c++20 %s + +namespace std { + inline namespace __1 { + template<bool, class = void> struct enable_if {}; + template<class T> struct enable_if<true, T> { using type = T; }; + template<bool B, class T = void> using enable_if_t = typename enable_if<B, T>::type; + } +} + +namespace similar_to_user_code { + // expected-note@+2 {{candidate template ignored: requirement 'sizeof(char) != 1' was not satisfied [with T = char]}} + template<class T, class = std::enable_if_t<sizeof(T) != 1>> + void f(T, short); + + // expected-note@+2 {{candidate template ignored: requirement 'sizeof(char) != 1' was not satisfied [with T = char]}} + template<class T, std::enable_if_t<sizeof(T) != 1>* = nullptr> + void f(T, int); + + // expected-note@+2 {{candidate template ignored: requirement 'sizeof(char) != 1' was not satisfied [with T = char]}} + template<class T> + std::enable_if_t<sizeof(T) != 1, void> f(T, long); + + void test() { + f('x', 0); // expected-error{{no matching function}} + } +} + +namespace similar_to_libcxx_version_14 { + template<bool, class = void> struct enable_if {}; + template<class T> struct enable_if<true, T> { using type = T; }; + template<bool B, class T = void> using __enable_if_t = typename enable_if<B, T>::type; + + // expected-note@+2 {{candidate template ignored: requirement 'sizeof(char) != 1' was not satisfied [with T = char]}} + template<class T, class = __enable_if_t<sizeof(T) != 1>> + void f(T, short); + + // expected-note@+2 {{candidate template ignored: requirement 'sizeof(char) != 1' was not satisfied [with T = char]}} + template<class T, __enable_if_t<sizeof(T) != 1>* = nullptr> + void f(T, int); + + // expected-note@+2 {{candidate template ignored: requirement 'sizeof(char) != 1' was not satisfied [with T = char]}} + template<class T> + __enable_if_t<sizeof(T) != 1, void> f(T, long); + + void test() { + f('x', 0); // expected-error{{no matching function}} + } +} + +namespace similar_to_libcxx_version_13 { + template<bool> struct _MetaBase {}; + template<> struct _MetaBase<true> { template<class R> using _EnableIfImpl = R; }; + template<bool B, class T = void> using _EnableIf = typename _MetaBase<B>::template _EnableIfImpl<T>; + + // expected-note@+2 {{no member named '_EnableIfImpl'}} + template<class T, class = _EnableIf<sizeof(T) != 1>> + void f(T, short); + + // expected-note@+2 {{no member named '_EnableIfImpl'}} + template<class T, _EnableIf<sizeof(T) != 1>* = nullptr> + void f(T, int); + + // expected-note@+2 {{no member named '_EnableIfImpl'}} + template<class T> + _EnableIf<sizeof(T) != 1, void> f(T, long); + + void test() { + f('x', 0); // expected-error{{no matching function}} + } +} + +namespace not_all_names_are_magic { + template<bool, class = void> struct enable_if {}; + template<class T> struct enable_if<true, T> { using type = T; }; + template<bool B, class T = void> using a_pony = typename enable_if<B, T>::type; + + // expected-note@-2 {{candidate template ignored: disabled by 'enable_if' [with T = char]}} + template<class T, class = a_pony<sizeof(T) != 1>> + void f(T, short); + + // expected-note@-6 {{candidate template ignored: disabled by 'enable_if' [with T = char]}} + template<class T, a_pony<sizeof(T) != 1>* = nullptr> + void f(T, int); + + // expected-note@-10 {{candidate template ignored: disabled by 'enable_if' [with T = char]}} + template<class T> + a_pony<sizeof(T) != 1, void> f(T, long); + + void test() { + f('x', 0); // expected-error{{no matching function}} + } +} Index: clang/lib/Sema/SemaTemplate.cpp =================================================================== --- clang/lib/Sema/SemaTemplate.cpp +++ clang/lib/Sema/SemaTemplate.cpp @@ -3511,8 +3511,10 @@ } /// Determine whether this alias template is "enable_if_t". +/// libc++ >=14 uses "__enable_if_t" in C++11 mode. static bool isEnableIfAliasTemplate(TypeAliasTemplateDecl *AliasTemplate) { - return AliasTemplate->getName().equals("enable_if_t"); + return AliasTemplate->getName().equals("enable_if_t") || + AliasTemplate->getName().equals("__enable_if_t"); } /// Collect all of the separable terms in the given condition, which
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits