[llvm-branch-commits] [clang] fbb83f1 - PR24076, PR33655, C++ CWG 1558: Consider the instantiation-dependence of
Richard Smith via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Mon Jan 18 21:09:59 PST 2021
Author: Richard Smith
Date: 2021-01-18T21:05:01-08:00
New Revision: fbb83f18b5485218ad3c36c1d079c89f061372b8
URL: https://github.com/llvm/llvm-project/commit/fbb83f18b5485218ad3c36c1d079c89f061372b8
DIFF: https://github.com/llvm/llvm-project/commit/fbb83f18b5485218ad3c36c1d079c89f061372b8.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.
Previously reverted in 25a02c3d1a688d3cd18faef96c75fa553efbbac7 due to
causing us to reject some code. It turns out that the rejected code was
ill-formed (no diagnostic required).
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 143a05cba6ad..319d3850346b 100644
--- a/clang/include/clang/AST/Type.h
+++ b/clang/include/clang/AST/Type.h
@@ -5412,7 +5412,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 1f8c11f6de96..084a0b0c5bf0 100644
--- a/clang/lib/AST/ItaniumMangle.cpp
+++ b/clang/lib/AST/ItaniumMangle.cpp
@@ -2583,6 +2583,10 @@ void CXXNameMangler::mangleType(QualType T) {
if (isa<DecltypeType, TypeOfType>(T))
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..2b9a47ad25a4
--- /dev/null
+++ b/clang/test/SemaTemplate/instantiation-dependence.cpp
@@ -0,0 +1,82 @@
+// 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}}
+}
+
+namespace TypeQualifier {
+ // Ensure that we substitute into an instantiation-dependent but
+ // non-dependent qualifier.
+ template<int> struct A { using type = int; };
+ template<typename T> A<sizeof(sizeof(T::error))>::type f() {} // expected-note {{'int' cannot be used prior to '::'}}
+ int k = f<int>(); // expected-error {{no matching}}
+}
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 at -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 f85bc49bb3d0..9be6f1262b68 100755
--- a/clang/www/cxx_dr_status.html
+++ b/clang/www/cxx_dr_status.html
@@ -9162,7 +9162,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>
More information about the llvm-branch-commits
mailing list