diff options
| author | Richard Smith <richard@metafoo.co.uk> | 2020-03-09 17:34:33 -0700 |
|---|---|---|
| committer | Hans Wennborg <hans@chromium.org> | 2020-03-12 12:10:24 +0100 |
| commit | d9bd6e3c1943e03b783f11d9f2e224ff83f83a7b (patch) | |
| tree | 16f09db3551e9ad0ed5a7f345d319442e6efd6ce /clang/test | |
| parent | 5e062819d5adeb2526f1b8393edf5a265bef1591 (diff) | |
| download | bcm5719-llvm-d9bd6e3c1943e03b783f11d9f2e224ff83f83a7b.tar.gz bcm5719-llvm-d9bd6e3c1943e03b783f11d9f2e224ff83f83a7b.zip | |
PR45083: Mark statement expressions as being dependent if they appear in
a dependent context.
This matches the GCC behavior.
We track the enclosing template depth when determining whether a
statement expression is within a dependent context; there doesn't appear
to be any other reliable way to determine this.
We previously assumed they were neither value- nor
instantiation-dependent under any circumstances, which would lead to
crashes and other misbehavior.
(cherry picked from commit 5c845c1c50ac89a6f12557d1571678f3d1432478)
Diffstat (limited to 'clang/test')
| -rw-r--r-- | clang/test/SemaTemplate/dependent-expr.cpp | 69 |
1 files changed, 67 insertions, 2 deletions
diff --git a/clang/test/SemaTemplate/dependent-expr.cpp b/clang/test/SemaTemplate/dependent-expr.cpp index bb1e239c349..0ce4cb39d34 100644 --- a/clang/test/SemaTemplate/dependent-expr.cpp +++ b/clang/test/SemaTemplate/dependent-expr.cpp @@ -1,5 +1,4 @@ -// RUN: %clang_cc1 -fsyntax-only -verify %s -// expected-no-diagnostics +// RUN: %clang_cc1 -fsyntax-only -verify -std=c++2a %s // PR5908 template <typename Iterator> @@ -108,3 +107,69 @@ namespace PR18152 { }; template struct A<0>; } + +template<typename T> void stmt_expr_1() { + static_assert( ({ false; }), "" ); +} +void stmt_expr_2() { + static_assert( ({ false; }), "" ); // expected-error {{failed}} +} + +namespace PR45083 { + struct A { bool x; }; + + template<typename> struct B : A { + void f() { + const int n = ({ if (x) {} 0; }); + } + }; + + template void B<int>::f(); + + template<typename> void f() { + decltype(({})) x; // expected-error {{incomplete type}} + } + template void f<int>(); // expected-note {{instantiation of}} + + template<typename> auto g() { + auto c = [](auto, int) -> decltype(({})) {}; + using T = decltype(c(0.0, 0)); + using T = void; + return c(0, 0); + } + using U = decltype(g<int>()); // expected-note {{previous}} + using U = float; // expected-error {{different types ('float' vs 'decltype(g<int>())' (aka 'void'))}} + + void h(auto a, decltype(g<char>())*) {} // expected-note {{previous}} + void h(auto a, void*) {} // expected-error {{redefinition}} + + void i(auto a) { + [](auto a, int = ({decltype(a) i; i * 2;})){}(a); // expected-error {{no matching function}} expected-note {{substitution failure}} + } + void use_i() { + i(0); + i((void*)0); // expected-note {{instantiation of}} + } +} + +namespace BindingInStmtExpr { + template<class ...Ts> struct overload : Ts... { + overload(Ts ...ts) : Ts(decltype(ts)(ts))... {} + using Ts::operator()...; + }; + + template<int> struct N {}; + + template<class T> auto num_bindings() { + auto f0 = [](auto t, unsigned) { return N<0>(); }; + auto f1 = [](auto t, int) -> decltype(({ auto [_1] = t; N<1>(); })) { return {}; }; + auto f2 = [](auto t, int) -> decltype(({ auto [_1, _2] = t; N<2>(); })) { return {}; }; + auto f3 = [](auto t, int) -> decltype(({ auto [_1, _2, _3] = t; N<3>(); })) { return {}; }; + return decltype(overload(f0, f1, f2, f3)(T(), 0))(); + } + + struct T { int a; int b; }; + // Make sure we get a correct, non-dependent type back. + using U = decltype(num_bindings<T>()); // expected-note {{previous}} + using U = N<3>; // expected-error-re {{type alias redefinition with different types ('N<3>' vs {{.*}}N<2>}} +} |

