[clang] ccca93b - Don't allow structured binding declarations to decompose a

Richard Smith via cfe-commits cfe-commits at lists.llvm.org
Fri Oct 23 16:28:36 PDT 2020


Author: Richard Smith
Date: 2020-10-23T16:28:25-07:00
New Revision: ccca93b5a2cb284dcdfecd34db1ca14632d6a1c1

URL: https://github.com/llvm/llvm-project/commit/ccca93b5a2cb284dcdfecd34db1ca14632d6a1c1
DIFF: https://github.com/llvm/llvm-project/commit/ccca93b5a2cb284dcdfecd34db1ca14632d6a1c1.diff

LOG: Don't allow structured binding declarations to decompose a
lambda-expression's captures.

The built-in structured binding rules for classes require that all
fields can be accessed by name, and the fields introduced for lambda
captures are unnamed, so decomposing a capturing lambda is ill-formed.

Added: 
    

Modified: 
    clang/include/clang/Basic/DiagnosticSemaKinds.td
    clang/lib/Sema/SemaDeclCXX.cpp
    clang/test/SemaCXX/cxx1z-decomposition.cpp

Removed: 
    


################################################################################
diff  --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 641d3e73905e..1aa6064d2210 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -486,6 +486,8 @@ def err_decomp_decl_inaccessible_base : Error<
 def err_decomp_decl_inaccessible_field : Error<
   "cannot decompose %select{private|protected}0 member %1 of %3">,
   AccessControl;
+def err_decomp_decl_lambda : Error<
+  "cannot decompose lambda closure type">;
 def err_decomp_decl_anon_union_member : Error<
   "cannot decompose class type %0 because it has an anonymous "
   "%select{struct|union}1 member">;

diff  --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index 72dfa37c321e..6589b37338e9 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -1374,11 +1374,23 @@ static bool checkMemberDecomposition(Sema &S, ArrayRef<BindingDecl*> Bindings,
     if (FD->isUnnamedBitfield())
       continue;
 
-    if (FD->isAnonymousStructOrUnion()) {
-      S.Diag(Src->getLocation(), diag::err_decomp_decl_anon_union_member)
-        << DecompType << FD->getType()->isUnionType();
-      S.Diag(FD->getLocation(), diag::note_declared_at);
-      return true;
+    // All the non-static data members are required to be nameable, so they
+    // must all have names.
+    if (!FD->getDeclName()) {
+      if (RD->isLambda()) {
+        S.Diag(Src->getLocation(), diag::err_decomp_decl_lambda);
+        S.Diag(RD->getLocation(), diag::note_lambda_decl);
+        return true;
+      }
+
+      if (FD->isAnonymousStructOrUnion()) {
+        S.Diag(Src->getLocation(), diag::err_decomp_decl_anon_union_member)
+          << DecompType << FD->getType()->isUnionType();
+        S.Diag(FD->getLocation(), diag::note_declared_at);
+        return true;
+      }
+
+      // FIXME: Are there any other ways we could have an anonymous member?
     }
 
     // We have a real field to bind.

diff  --git a/clang/test/SemaCXX/cxx1z-decomposition.cpp b/clang/test/SemaCXX/cxx1z-decomposition.cpp
index 336c103ef0a4..45a062a916f3 100644
--- a/clang/test/SemaCXX/cxx1z-decomposition.cpp
+++ b/clang/test/SemaCXX/cxx1z-decomposition.cpp
@@ -103,4 +103,49 @@ int f2() {
 
 } // namespace instantiate_template
 
+namespace lambdas {
+  void f() {
+    int n;
+    auto [a] =  // expected-error {{cannot decompose lambda closure type}}
+        [n] {}; // expected-note {{lambda expression}}
+  }
+
+  auto [] = []{}; // expected-warning {{ISO C++17 does not allow a decomposition group to be empty}}
+
+  int g() {
+    int n = 0;
+    auto a = [=](auto &self) { // expected-note {{lambda expression}}
+      auto &[capture] = self; // expected-error {{cannot decompose lambda closure type}}
+      ++capture;
+      return n;
+    };
+    return a(a); // expected-note {{in instantiation of}}
+  }
+
+  int h() {
+    auto x = [] {};
+    struct A : decltype(x) {
+      int n;
+    };
+    auto &&[r] = A{x, 0}; // OK (presumably), non-capturing lambda has no non-static data members
+    return r;
+  }
+
+  int i() {
+    int n;
+    auto x = [n] {};
+    struct A : decltype(x) {
+      int n;
+    };
+    auto &&[r] = A{x, 0}; // expected-error-re {{cannot decompose class type 'A': both it and its base class 'decltype(x)' (aka '(lambda {{.*}})') have non-static data members}}
+    return r;
+  }
+
+  void j() {
+    auto x = [] {};
+    struct A : decltype(x) {};
+    auto &&[] = A{x}; // expected-warning {{ISO C++17 does not allow a decomposition group to be empty}}
+  }
+}
+
 // FIXME: by-value array copies


        


More information about the cfe-commits mailing list