Author: Richard Smith Date: 2020-12-17T21:31:23-08:00 New Revision: d3bf0bb18952d830fe6df6f791a64552b271000b
URL: https://github.com/llvm/llvm-project/commit/d3bf0bb18952d830fe6df6f791a64552b271000b DIFF: https://github.com/llvm/llvm-project/commit/d3bf0bb18952d830fe6df6f791a64552b271000b.diff LOG: PR24076, PR33655, C++ CWG 1558: Consider the instantiation-dependence of the nested-name-specifier when determining whether a qualified type is instantiation-dependent. Added: clang/test/SemaTemplate/instantiation-dependence.cpp Modified: clang/include/clang/AST/Type.h clang/lib/AST/ItaniumMangle.cpp clang/test/CXX/drs/dr15xx.cpp clang/test/CodeGenCXX/mangle-template.cpp clang/test/SemaTemplate/partial-spec-instantiate.cpp clang/www/cxx_dr_status.html Removed: ################################################################################ diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h index 945ea7a600c0..a3059b83c1be 100644 --- a/clang/include/clang/AST/Type.h +++ b/clang/include/clang/AST/Type.h @@ -5398,7 +5398,9 @@ class ElaboratedType final ElaboratedType(ElaboratedTypeKeyword Keyword, NestedNameSpecifier *NNS, QualType NamedType, QualType CanonType, TagDecl *OwnedTagDecl) : TypeWithKeyword(Keyword, Elaborated, CanonType, - NamedType->getDependence()), + NamedType->getDependence() | + (NNS ? toTypeDependence(NNS->getDependence()) + : TypeDependence::None)), NNS(NNS), NamedType(NamedType) { ElaboratedTypeBits.HasOwnedTagDecl = false; if (OwnedTagDecl) { diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp index 73c8f17a5d36..6c8d5687c64a 100644 --- a/clang/lib/AST/ItaniumMangle.cpp +++ b/clang/lib/AST/ItaniumMangle.cpp @@ -2578,6 +2578,10 @@ void CXXNameMangler::mangleType(QualType T) { if (!TST->isTypeAlias()) break; + // FIXME: We presumably shouldn't strip off ElaboratedTypes with + // instantation-dependent qualifiers. See + // https://github.com/itanium-cxx-abi/cxx-abi/issues/114. + QualType Desugared = T.getSingleStepDesugaredType(Context.getASTContext()); if (Desugared == T) diff --git a/clang/test/CXX/drs/dr15xx.cpp b/clang/test/CXX/drs/dr15xx.cpp index 478a0d7d00dd..8bfa29a8b667 100644 --- a/clang/test/CXX/drs/dr15xx.cpp +++ b/clang/test/CXX/drs/dr15xx.cpp @@ -239,6 +239,20 @@ namespace dr1550 { // dr1550: yes } } +namespace dr1558 { // dr1558: 12 +#if __cplusplus >= 201103L + template<class T, class...> using first_of = T; + template<class T> first_of<void, typename T::type> f(int); // expected-note {{'int' cannot be used prior to '::'}} + template<class T> void f(...) = delete; // expected-note {{deleted}} + + struct X { typedef void type; }; + void test() { + f<X>(0); + f<int>(0); // expected-error {{deleted}} + } +#endif +} + namespace dr1560 { // dr1560: 3.5 void f(bool b, int n) { (b ? throw 0 : n) = (b ? n : throw 0) = 0; diff --git a/clang/test/CodeGenCXX/mangle-template.cpp b/clang/test/CodeGenCXX/mangle-template.cpp index 9b5220572c2e..40688de7e12e 100644 --- a/clang/test/CodeGenCXX/mangle-template.cpp +++ b/clang/test/CodeGenCXX/mangle-template.cpp @@ -342,3 +342,23 @@ namespace fixed_size_parameter_pack { template<int ...Ns> void f(A<unsigned, char, long long>::B<0, Ns...>); void g() { f<1, 2>({}); } } + +namespace type_qualifier { + template<typename T> using int_t = int; + template<typename T> void f(decltype(int_t<T*>() + 1)) {} + // FIXME: This mangling doesn't work: we need to mangle the + // instantiation-dependent 'int_t' operand. + // CHECK: @_ZN14type_qualifier1fIPiEEvDTplcvi_ELi1EE + template void f<int*>(int); + + // Note that this template has diff erent constraints but would mangle the + // same: + //template<typename T> void f(decltype(int_t<typename T::type>() + 1)) {} + + struct impl { using type = void; }; + template<typename T> using alias = impl; + template<typename T> void g(decltype(alias<T*>::type(), 1)) {} + // FIXME: Similarly we need to mangle the `T*` in here. + // CHECK: @_ZN14type_qualifier1gIPiEEvDTcmcvv_ELi1EE + template void g<int*>(int); +} diff --git a/clang/test/SemaTemplate/instantiation-dependence.cpp b/clang/test/SemaTemplate/instantiation-dependence.cpp new file mode 100644 index 000000000000..75eb510cb68d --- /dev/null +++ b/clang/test/SemaTemplate/instantiation-dependence.cpp @@ -0,0 +1,74 @@ +// RUN: %clang_cc1 -std=c++2b -verify %s + +// Ensure we substitute into instantiation-dependent but non-dependent +// constructs. The poster-child for this is... +template<class ...> using void_t = void; + +namespace PR24076 { + template<class T> T declval(); + struct s {}; + + template<class T, + class = void_t<decltype(declval<T>() + 1)>> + void foo(T) {} // expected-note {{invalid operands to binary expression}} + + void f() { + foo(s{}); // expected-error {{no matching function}} + } + + template<class T, + class = void_t<decltype(declval<T>() + 1)>> // expected-error {{invalid operands to binary expression}} + struct bar {}; + + bar<s> bar; // expected-note {{in instantiation of}} +} + +namespace PR33655 { + struct One { using x = int; }; + struct Two { using y = int; }; + + template<typename T, void_t<typename T::x> * = nullptr> int &func() {} + template<typename T, void_t<typename T::y> * = nullptr> float &func() {} + + int &test1 = func<One>(); + float &test2 = func<Two>(); + + template<class ...Args> struct indirect_void_t_imp { using type = void; }; + template<class ...Args> using indirect_void_t = typename indirect_void_t_imp<Args...>::type; + + template<class T> void foo() { + static_assert(!__is_void(indirect_void_t<T>)); // "ok", dependent + static_assert(!__is_void(void_t<T>)); // expected-error {{failed}} + } +} + +namespace PR46791 { // also PR45782 + template<typename T, typename = void> + struct trait { + static constexpr int specialization = 0; + }; + + // FIXME: Per a strict interpretation of the C++ rules, the two void_t<...> + // types below are equivalent -- we only (effectively) do token-by-token + // comparison for *expressions* appearing within types. But all other + // implementations accept this, using rules that are unclear. + template<typename T> + struct trait<T, void_t<typename T::value_type>> { // expected-note {{previous}} FIXME-note {{matches}} + static constexpr int specialization = 1; + }; + + template<typename T> + struct trait<T, void_t<typename T::element_type>> { // expected-error {{redefinition}} FIXME-note {{matches}} + static constexpr int specialization = 2; + }; + + struct A {}; + struct B { typedef int value_type; }; + struct C { typedef int element_type; }; + struct D : B, C {}; + + static_assert(trait<A>::specialization == 0); + static_assert(trait<B>::specialization == 1); // FIXME expected-error {{failed}} + static_assert(trait<C>::specialization == 2); // FIXME expected-error {{failed}} + static_assert(trait<D>::specialization == 0); // FIXME-error {{ambiguous partial specialization}} +} diff --git a/clang/test/SemaTemplate/partial-spec-instantiate.cpp b/clang/test/SemaTemplate/partial-spec-instantiate.cpp index 2fc0517ae3d3..3b7cee88c42e 100644 --- a/clang/test/SemaTemplate/partial-spec-instantiate.cpp +++ b/clang/test/SemaTemplate/partial-spec-instantiate.cpp @@ -51,8 +51,6 @@ namespace rdar9169404 { X<bool, -1>::type value; #if __cplusplus >= 201103L // expected-error@-2 {{non-type template argument evaluates to -1, which cannot be narrowed to type 'bool'}} -#else - // expected-no-diagnostics #endif } @@ -98,3 +96,19 @@ namespace rdar39524996 { takesWrapperInContainer(c); } } + +namespace InstantiationDependent { + template<typename> using ignore = void; // expected-warning 0-1{{extension}} + template<typename T, typename = void> struct A { + static const bool specialized = false; + }; + template<typename T> struct Hide { typedef void type; }; + template<typename T> struct A<T, Hide<ignore<typename T::type> >::type> { + static const bool specialized = true; + }; + + struct X {}; + struct Y { typedef int type; }; + _Static_assert(!A<X>::specialized, ""); + _Static_assert(A<Y>::specialized, ""); +} diff --git a/clang/www/cxx_dr_status.html b/clang/www/cxx_dr_status.html index 6e0206ab9e63..feac3c6dc2d0 100755 --- a/clang/www/cxx_dr_status.html +++ b/clang/www/cxx_dr_status.html @@ -9163,7 +9163,7 @@ <h2 id="cxxdr">C++ defect report implementation status</h2> <td><a href="https://wg21.link/cwg1558">1558</a></td> <td>CD4</td> <td>Unused arguments in alias template specializations</td> - <td class="none" align="center">Unknown</td> + <td class="unreleased" align="center">Clang 12</td> </tr> <tr id="1559"> <td><a href="https://wg21.link/cwg1559">1559</a></td> _______________________________________________ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits