]> granicus.if.org Git - clang/commitdiff
Part of P1091R3: permit structured bindings to be declared 'static' and
authorRichard Smith <richard-llvm@metafoo.co.uk>
Wed, 22 May 2019 19:52:55 +0000 (19:52 +0000)
committerRichard Smith <richard-llvm@metafoo.co.uk>
Wed, 22 May 2019 19:52:55 +0000 (19:52 +0000)
'thread_local' in C++20.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@361424 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Basic/DiagnosticSemaKinds.td
lib/Sema/SemaDeclCXX.cpp
test/CodeGenCXX/cxx1z-decomposition.cpp
test/Parser/cxx1z-decomposition.cpp
test/SemaCXX/cxx17-compat.cpp
test/SemaCXX/cxx1z-decomposition.cpp
www/cxx_status.html

index 48b0ec4b378e1b16c5b70d4e3de486875a70cdeb..7e03174b3d00471196d1282cb0f0615201fd37d8 100644 (file)
@@ -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'">;
index 99dd96c39da34b53accf9a654897e4612dd7d4d4..b3920ff01bdff7265ae0d07522fb5e65f1bcaa01 100644 (file)
@@ -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)
index b9212006053b9c27ebd698144915ce765d04915d..8e71b1230c4d5a037fe6038121ce8e3d8317e8c8 100644 (file)
@@ -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)
+}
index 1e184a7fac540a4a504347944083e7ced6971312..ccd77064a2342279f347144a1988a89bf1990fb3 100644 (file)
@@ -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;
index 5fcec2ab9cce4620a182cb0072c703f93fbfd2d0..3d5420fa06377226691d2fe1f428cd4d51046c30 100644 (file)
@@ -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
+}
index 8b5fd6809bb4cefdebdedbd1699fcf39959f665e..f174c79e5957343c3f99b9e4041214ac05f2b9ff 100644 (file)
@@ -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 {
index 901cea861e748efb3d48d35521ce98a1f2730948..1a6477665b046e4d8b83b7ec2882ebb27b70d2a6 100755 (executable)
@@ -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>