summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRichard Smith <richard-llvm@metafoo.co.uk>2019-05-22 19:52:55 +0000
committerRichard Smith <richard-llvm@metafoo.co.uk>2019-05-22 19:52:55 +0000
commit13bf9892dc2a37a4c4a0fcce8cb79ed8798a236f (patch)
tree7de36123533f812e0fcea10b020e7eb2a1c8556b
parent6dbf4a86a7c8d2a63aebb96c3e7d1ac477a40d9e (diff)
downloadbcm5719-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.td9
-rw-r--r--clang/lib/Sema/SemaDeclCXX.cpp30
-rw-r--r--clang/test/CodeGenCXX/cxx1z-decomposition.cpp47
-rw-r--r--clang/test/Parser/cxx1z-decomposition.cpp10
-rw-r--r--clang/test/SemaCXX/cxx17-compat.cpp16
-rw-r--r--clang/test/SemaCXX/cxx1z-decomposition.cpp2
-rwxr-xr-xclang/www/cxx_status.html2
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>
OpenPOWER on IntegriCloud