diff options
author | Hans Wennborg <hans@hanshq.net> | 2019-08-20 10:00:41 +0000 |
---|---|---|
committer | Hans Wennborg <hans@hanshq.net> | 2019-08-20 10:00:41 +0000 |
commit | 116ea3bb7a5fadc78fec76e9449013902bf19242 (patch) | |
tree | 2dbbbb91a7984f3bff19581bc646f75730b50ba9 | |
parent | be6ed962cfe0cc61250a514e2c98feb4e08d45ad (diff) |
Merging r369043:
------------------------------------------------------------------------
r369043 | rnk | 2019-08-15 21:45:28 +0200 (Thu, 15 Aug 2019) | 15 lines
[Sema] Implement DR2386 for C++17 structured binding
Allow implementations to provide complete definitions of
std::tuple_size<T>, but to omit the 'value' member to signal that T is
not tuple-like. The Microsoft standard library implements
std::tuple_size<const T> this way.
If the value member exists, clang still validates that it is an ICE, but
if it does not, then the type is considered to not be tuple-like.
Fixes PR33236
Reviewers: rsmith
Differential Revision: https://reviews.llvm.org/D66040
------------------------------------------------------------------------
git-svn-id: https://llvm.org/svn/llvm-project/cfe/branches/release_90@369361 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | lib/Sema/SemaDeclCXX.cpp | 11 | ||||
-rw-r--r-- | test/CXX/dcl.decl/dcl.decomp/p3.cpp | 2 | ||||
-rw-r--r-- | test/CXX/drs/dr23xx.cpp | 21 |
3 files changed, 26 insertions, 8 deletions
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index 2ffb0b4892..15984f89e2 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -1030,8 +1030,10 @@ static IsTupleLike isTupleLike(Sema &S, SourceLocation Loc, QualType T, TemplateArgumentListInfo Args(Loc, Loc); Args.addArgument(getTrivialTypeTemplateArgument(S, Loc, T)); - // If there's no tuple_size specialization, it's not tuple-like. - if (lookupStdTypeTraitMember(S, R, Loc, "tuple_size", Args, /*DiagID*/0)) + // If there's no tuple_size specialization or the lookup of 'value' is empty, + // it's not tuple-like. + if (lookupStdTypeTraitMember(S, R, Loc, "tuple_size", Args, /*DiagID*/ 0) || + R.empty()) return IsTupleLike::NotTupleLike; // If we get this far, we've committed to the tuple interpretation, but @@ -1048,11 +1050,6 @@ static IsTupleLike isTupleLike(Sema &S, SourceLocation Loc, QualType T, } } Diagnoser(R, Args); - if (R.empty()) { - Diagnoser.diagnoseNotICE(S, Loc, SourceRange()); - return IsTupleLike::Error; - } - ExprResult E = S.BuildDeclarationNameExpr(CXXScopeSpec(), R, /*NeedsADL*/false); if (E.isInvalid()) diff --git a/test/CXX/dcl.decl/dcl.decomp/p3.cpp b/test/CXX/dcl.decl/dcl.decomp/p3.cpp index b3f0cf1874..9b030c1a2e 100644 --- a/test/CXX/dcl.decl/dcl.decomp/p3.cpp +++ b/test/CXX/dcl.decl/dcl.decomp/p3.cpp @@ -12,7 +12,7 @@ void no_tuple_size_2() { auto [x, y] = A(); } // ok, decompose elementwise struct Bad1 { int a, b; }; template<> struct std::tuple_size<Bad1> {}; -void no_tuple_size_3() { auto [x, y] = Bad1(); } // expected-error {{cannot decompose this type; 'std::tuple_size<Bad1>::value' is not a valid integral constant expression}} +void no_tuple_size_3() { auto [x, y] = Bad1(); } // ok, omitting value is valid after DR2386 struct Bad2 {}; template<> struct std::tuple_size<Bad2> { const int value = 5; }; diff --git a/test/CXX/drs/dr23xx.cpp b/test/CXX/drs/dr23xx.cpp index 8e7a9a880b..763abd5368 100644 --- a/test/CXX/drs/dr23xx.cpp +++ b/test/CXX/drs/dr23xx.cpp @@ -40,6 +40,27 @@ namespace dr2353 { // dr2353: 9 #pragma clang __debug dump not_use_2 } +#if __cplusplus >= 201707L +// Otherwise, if the qualified-id std::tuple_size<E> names a complete class +// type **with a member value**, the expression std::tuple_size<E>::value shall +// be a well-formed integral constant expression +namespace dr2386 { // dr2386: 9 +struct Bad1 { int a, b; }; +struct Bad2 { int a, b; }; +} // namespace dr2386 +namespace std { +template <typename T> struct tuple_size; +template <> struct std::tuple_size<dr2386::Bad1> {}; +template <> struct std::tuple_size<dr2386::Bad2> { + static const int value = 42; +}; +} // namespace std +namespace dr2386 { +void no_value() { auto [x, y] = Bad1(); } +void wrong_value() { auto [x, y] = Bad2(); } // expected-error {{decomposes into 42 elements}} +} // namespace dr2386 +#endif + namespace dr2387 { // dr2387: 9 #if __cplusplus >= 201402L template<int> int a = 0; |