diff options
author | Richard Smith <richard-llvm@metafoo.co.uk> | 2019-05-22 19:52:55 +0000 |
---|---|---|
committer | Richard Smith <richard-llvm@metafoo.co.uk> | 2019-05-22 19:52:55 +0000 |
commit | 13bf9892dc2a37a4c4a0fcce8cb79ed8798a236f (patch) | |
tree | 7de36123533f812e0fcea10b020e7eb2a1c8556b | |
parent | 6dbf4a86a7c8d2a63aebb96c3e7d1ac477a40d9e (diff) | |
download | bcm5719-llvm-13bf9892dc2a37a4c4a0fcce8cb79ed8798a236f.tar.gz bcm5719-llvm-13bf9892dc2a37a4c4a0fcce8cb79ed8798a236f.zip |
Part of P1091R3: permit structured bindings to be declared 'static' and
'thread_local' in C++20.
llvm-svn: 361424
-rw-r--r-- | clang/include/clang/Basic/DiagnosticSemaKinds.td | 9 | ||||
-rw-r--r-- | clang/lib/Sema/SemaDeclCXX.cpp | 30 | ||||
-rw-r--r-- | clang/test/CodeGenCXX/cxx1z-decomposition.cpp | 47 | ||||
-rw-r--r-- | clang/test/Parser/cxx1z-decomposition.cpp | 10 | ||||
-rw-r--r-- | clang/test/SemaCXX/cxx17-compat.cpp | 16 | ||||
-rw-r--r-- | clang/test/SemaCXX/cxx1z-decomposition.cpp | 2 | ||||
-rwxr-xr-x | clang/www/cxx_status.html | 2 |
7 files changed, 105 insertions, 11 deletions
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 48b0ec4b378..7e03174b3d0 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -417,6 +417,15 @@ def ext_decomp_decl_cond : ExtWarn< def err_decomp_decl_spec : Error< "decomposition declaration cannot be declared " "%plural{1:'%1'|:with '%1' specifiers}0">; +def ext_decomp_decl_spec : ExtWarn< + "decomposition declaration declared " + "%plural{1:'%1'|:with '%1' specifiers}0 is a C++2a extension">, + InGroup<CXX2a>; +def warn_cxx17_compat_decomp_decl_spec : Warning< + "decomposition declaration declared " + "%plural{1:'%1'|:with '%1' specifiers}0 " + "is incompatible with C++ standards before C++2a">, + InGroup<CXXPre2aCompat>, DefaultIgnore; def err_decomp_decl_type : Error< "decomposition declaration cannot be declared with type %0; " "declared type must be 'auto' or reference to 'auto'">; diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 99dd96c39da..b3920ff01bd 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -715,20 +715,30 @@ Sema::ActOnDecompositionDeclarator(Scope *S, Declarator &D, // The semantic context is always just the current context. DeclContext *const DC = CurContext; - // C++1z [dcl.dcl]/8: + // C++17 [dcl.dcl]/8: // The decl-specifier-seq shall contain only the type-specifier auto // and cv-qualifiers. + // C++2a [dcl.dcl]/8: + // If decl-specifier-seq contains any decl-specifier other than static, + // thread_local, auto, or cv-qualifiers, the program is ill-formed. auto &DS = D.getDeclSpec(); { SmallVector<StringRef, 8> BadSpecifiers; SmallVector<SourceLocation, 8> BadSpecifierLocs; + SmallVector<StringRef, 8> CPlusPlus20Specifiers; + SmallVector<SourceLocation, 8> CPlusPlus20SpecifierLocs; if (auto SCS = DS.getStorageClassSpec()) { - BadSpecifiers.push_back(DeclSpec::getSpecifierName(SCS)); - BadSpecifierLocs.push_back(DS.getStorageClassSpecLoc()); + if (SCS == DeclSpec::SCS_static) { + CPlusPlus20Specifiers.push_back(DeclSpec::getSpecifierName(SCS)); + CPlusPlus20SpecifierLocs.push_back(DS.getStorageClassSpecLoc()); + } else { + BadSpecifiers.push_back(DeclSpec::getSpecifierName(SCS)); + BadSpecifierLocs.push_back(DS.getStorageClassSpecLoc()); + } } if (auto TSCS = DS.getThreadStorageClassSpec()) { - BadSpecifiers.push_back(DeclSpec::getSpecifierName(TSCS)); - BadSpecifierLocs.push_back(DS.getThreadStorageClassSpecLoc()); + CPlusPlus20Specifiers.push_back(DeclSpec::getSpecifierName(TSCS)); + CPlusPlus20SpecifierLocs.push_back(DS.getThreadStorageClassSpecLoc()); } if (DS.isConstexprSpecified()) { BadSpecifiers.push_back("constexpr"); @@ -746,6 +756,16 @@ Sema::ActOnDecompositionDeclarator(Scope *S, Declarator &D, // them when building the underlying variable. for (auto Loc : BadSpecifierLocs) Err << SourceRange(Loc, Loc); + } else if (!CPlusPlus20Specifiers.empty()) { + auto &&Warn = Diag(CPlusPlus20SpecifierLocs.front(), + getLangOpts().CPlusPlus2a + ? diag::warn_cxx17_compat_decomp_decl_spec + : diag::ext_decomp_decl_spec); + Warn << (int)CPlusPlus20Specifiers.size() + << llvm::join(CPlusPlus20Specifiers.begin(), + CPlusPlus20Specifiers.end(), " "); + for (auto Loc : CPlusPlus20SpecifierLocs) + Warn << SourceRange(Loc, Loc); } // We can't recover from it being declared as a typedef. if (DS.getStorageClassSpec() == DeclSpec::SCS_typedef) diff --git a/clang/test/CodeGenCXX/cxx1z-decomposition.cpp b/clang/test/CodeGenCXX/cxx1z-decomposition.cpp index b9212006053..8e71b1230c4 100644 --- a/clang/test/CodeGenCXX/cxx1z-decomposition.cpp +++ b/clang/test/CodeGenCXX/cxx1z-decomposition.cpp @@ -116,3 +116,50 @@ void test_bitfield(A &a) { // CHECK: or i16 %{{.*}}, 5 // CHECK: store i16 %{{.*}}, i16* %[[BITFIELD]], } + +// CHECK-LABEL: define {{.*}}@_Z18test_static_simple +void test_static_simple() { + static auto [x1, x2] = make<A>(); + // CHECK: load atomic {{.*}}i64* @_ZGVZ18test_static_simplevEDC2x12x2E + // CHECK: br i1 + // CHECK: @__cxa_guard_acquire( + // CHECK: call {{.*}} @_Z4makeI1AERT_v( + // CHECK: memcpy{{.*}} @_ZZ18test_static_simplevEDC2x12x2E + // CHECK: @__cxa_guard_release( +} + +// CHECK-LABEL: define {{.*}}@_Z17test_static_tuple +void test_static_tuple() { + // Note that the desugaring specified for this construct requires three + // separate guarded initializations. It is possible for an exception to be + // thrown after the first initialization and before the second, and if that + // happens, we are not permitted to rerun the first initialization, so we + // can't combine these into a single guarded initialization in general. + static auto [x1, x2] = make<B>(); + + // Initialization of the implied variable. + // CHECK: load atomic {{.*}} @_ZGVZ17test_static_tuplevEDC2x12x2E + // CHECK: br i1 + // CHECK: @__cxa_guard_acquire({{.*}} @_ZGVZ17test_static_tuplevEDC2x12x2E) + // CHECK: call {{.*}} @_Z4makeI1BERT_v( + // CHECK: @__cxa_guard_release({{.*}} @_ZGVZ17test_static_tuplevEDC2x12x2E) + + // Initialization of the secret 'x1' variable. + // CHECK: load atomic {{.*}} @_ZGVZ17test_static_tuplevE2x1 + // CHECK: br i1 + // CHECK: @__cxa_guard_acquire({{.*}} @_ZGVZ17test_static_tuplevE2x1) + // CHECK: call {{.*}} @_Z3getILi0EEDa1B( + // CHECK: call {{.*}} @_ZN1XC1E1Y({{.*}} @_ZGRZ17test_static_tuplevE2x1_, + // CHECK: call {{.*}} @__cxa_atexit({{.*}} @_ZN1XD1Ev {{.*}} @_ZGRZ17test_static_tuplevE2x1_ + // CHECK: store {{.*}} @_ZGRZ17test_static_tuplevE2x1_, {{.*}} @_ZZ17test_static_tuplevE2x1 + // CHECK: call void @__cxa_guard_release({{.*}} @_ZGVZ17test_static_tuplevE2x1) + + // Initialization of the secret 'x2' variable. + // CHECK: load atomic {{.*}} @_ZGVZ17test_static_tuplevE2x2 + // CHECK: br i1 + // CHECK: @__cxa_guard_acquire({{.*}} @_ZGVZ17test_static_tuplevE2x2) + // CHECK: call {{.*}} @_Z3getILi1EEDa1B( + // CHECK: store {{.*}}, {{.*}} @_ZGRZ17test_static_tuplevE2x2_ + // CHECK: store {{.*}} @_ZGRZ17test_static_tuplevE2x2_, {{.*}} @_ZZ17test_static_tuplevE2x2 + // CHECK: call void @__cxa_guard_release({{.*}} @_ZGVZ17test_static_tuplevE2x2) +} diff --git a/clang/test/Parser/cxx1z-decomposition.cpp b/clang/test/Parser/cxx1z-decomposition.cpp index 1e184a7fac5..ccd77064a23 100644 --- a/clang/test/Parser/cxx1z-decomposition.cpp +++ b/clang/test/Parser/cxx1z-decomposition.cpp @@ -67,8 +67,8 @@ namespace BadSpecifiers { struct S { int n; } s; void f() { // storage-class-specifiers - static auto &[a] = n; // expected-error {{cannot be declared 'static'}} - thread_local auto &[b] = n; // expected-error {{cannot be declared 'thread_local'}} + static auto &[a] = n; // expected-warning {{declared 'static' is a C++2a extension}} + thread_local auto &[b] = n; // expected-warning {{declared 'thread_local' is a C++2a extension}} extern auto &[c] = n; // expected-error {{cannot be declared 'extern'}} expected-error {{cannot have an initializer}} struct S { mutable auto &[d] = n; // expected-error {{not permitted in this context}} @@ -82,9 +82,11 @@ namespace BadSpecifiers { }; typedef auto &[h] = n; // expected-error {{cannot be declared 'typedef'}} constexpr auto &[i] = n; // expected-error {{cannot be declared 'constexpr'}} - - static constexpr thread_local auto &[j] = n; // expected-error {{cannot be declared with 'static thread_local constexpr' specifiers}} } + + static constexpr inline thread_local auto &[j1] = n; // expected-error {{cannot be declared with 'constexpr inline' specifiers}} + static thread_local auto &[j2] = n; // expected-warning {{declared with 'static thread_local' specifiers is a C++2a extension}} + inline auto &[k] = n; // expected-error {{cannot be declared 'inline'}} const int K = 5; diff --git a/clang/test/SemaCXX/cxx17-compat.cpp b/clang/test/SemaCXX/cxx17-compat.cpp index 5fcec2ab9cc..3d5420fa063 100644 --- a/clang/test/SemaCXX/cxx17-compat.cpp +++ b/clang/test/SemaCXX/cxx17-compat.cpp @@ -72,3 +72,19 @@ struct ConstexprVirtual { // expected-warning@-4 {{virtual constexpr functions are incompatible with C++ standards before C++2a}} #endif }; + +struct C { int x, y, z; }; +static auto [cx, cy, cz] = C(); +#if __cplusplus <= 201703L + // expected-warning@-2 {{decomposition declaration declared 'static' is a C++2a extension}} +#else + // expected-warning@-4 {{decomposition declaration declared 'static' is incompatible with C++ standards before C++2a}} +#endif +void f() { + static thread_local auto [cx, cy, cz] = C(); +#if __cplusplus <= 201703L + // expected-warning@-2 {{decomposition declaration declared with 'static thread_local' specifiers is a C++2a extension}} +#else + // expected-warning@-4 {{decomposition declaration declared with 'static thread_local' specifiers is incompatible with C++ standards before C++2a}} +#endif +} diff --git a/clang/test/SemaCXX/cxx1z-decomposition.cpp b/clang/test/SemaCXX/cxx1z-decomposition.cpp index 8b5fd6809bb..f174c79e595 100644 --- a/clang/test/SemaCXX/cxx1z-decomposition.cpp +++ b/clang/test/SemaCXX/cxx1z-decomposition.cpp @@ -78,7 +78,7 @@ template <class T> void dependent_foreach(T t) { struct PR37352 { int n; - void f() { static auto [a] = *this; } // expected-error {{cannot be declared 'static'}} + void f() { static auto [a] = *this; } // expected-warning {{C++2a extension}} }; namespace instantiate_template { diff --git a/clang/www/cxx_status.html b/clang/www/cxx_status.html index 901cea861e7..1a6477665b0 100755 --- a/clang/www/cxx_status.html +++ b/clang/www/cxx_status.html @@ -1034,7 +1034,7 @@ as the draft C++2a standard evolves. <tr> <td rowspan="2">Structured binding extensions</td> <td><a href="http://wg21.link/p1091r3">P1091R3</a></td> - <td rowspan="2" class="none" align="center">No</td> + <td rowspan="2" class="partial" align="center">Partial</td> </tr> <tr> <td><a href="http://wg21.link/p1381r1">P1381R1</a></td> |