r361686 - Permit static local structured bindings to be named from arbitrary scopes inside their declaring scope.

Richard Smith via cfe-commits cfe-commits at lists.llvm.org
Fri May 24 18:04:18 PDT 2019


Author: rsmith
Date: Fri May 24 18:04:17 2019
New Revision: 361686

URL: http://llvm.org/viewvc/llvm-project?rev=361686&view=rev
Log:
Permit static local structured bindings to be named from arbitrary scopes inside their declaring scope.

Modified:
    cfe/trunk/include/clang/AST/DeclCXX.h
    cfe/trunk/lib/AST/DeclCXX.cpp
    cfe/trunk/lib/Sema/SemaExpr.cpp
    cfe/trunk/lib/Serialization/ASTReaderDecl.cpp
    cfe/trunk/test/CodeGenCXX/cxx1z-decomposition.cpp
    cfe/trunk/test/SemaCXX/cxx1z-decomposition.cpp

Modified: cfe/trunk/include/clang/AST/DeclCXX.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclCXX.h?rev=361686&r1=361685&r2=361686&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/DeclCXX.h (original)
+++ cfe/trunk/include/clang/AST/DeclCXX.h Fri May 24 18:04:17 2019
@@ -63,6 +63,7 @@ class CXXDestructorDecl;
 class CXXFinalOverriderMap;
 class CXXIndirectPrimaryBaseSet;
 class CXXMethodDecl;
+class DecompositionDecl;
 class DiagnosticBuilder;
 class FriendDecl;
 class FunctionTemplateDecl;
@@ -3918,6 +3919,8 @@ public:
 /// x[0], x[1], and x[2] respectively, where x is the implicit
 /// DecompositionDecl of type 'int (&)[3]'.
 class BindingDecl : public ValueDecl {
+  /// The declaration that this binding binds to part of.
+  LazyDeclPtr Decomp;
   /// The binding represented by this declaration. References to this
   /// declaration are effectively equivalent to this expression (except
   /// that it is only evaluated once at the point of declaration of the
@@ -3941,6 +3944,10 @@ public:
   /// decomposition declaration, and when the initializer is type-dependent.
   Expr *getBinding() const { return Binding; }
 
+  /// Get the decomposition declaration that this binding represents a
+  /// decomposition of.
+  ValueDecl *getDecomposedDecl() const;
+
   /// Get the variable (if any) that holds the value of evaluating the binding.
   /// Only present for user-defined bindings for tuple-like types.
   VarDecl *getHoldingVar() const;
@@ -3953,6 +3960,9 @@ public:
     this->Binding = Binding;
   }
 
+  /// Set the decomposed variable for this BindingDecl.
+  void setDecomposedDecl(ValueDecl *Decomposed) { Decomp = Decomposed; }
+
   static bool classof(const Decl *D) { return classofKind(D->getKind()); }
   static bool classofKind(Kind K) { return K == Decl::Binding; }
 };
@@ -3980,6 +3990,8 @@ class DecompositionDecl final
         NumBindings(Bindings.size()) {
     std::uninitialized_copy(Bindings.begin(), Bindings.end(),
                             getTrailingObjects<BindingDecl *>());
+    for (auto *B : Bindings)
+      B->setDecomposedDecl(this);
   }
 
   void anchor() override;

Modified: cfe/trunk/lib/AST/DeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclCXX.cpp?rev=361686&r1=361685&r2=361686&view=diff
==============================================================================
--- cfe/trunk/lib/AST/DeclCXX.cpp (original)
+++ cfe/trunk/lib/AST/DeclCXX.cpp Fri May 24 18:04:17 2019
@@ -2929,6 +2929,12 @@ BindingDecl *BindingDecl::CreateDeserial
   return new (C, ID) BindingDecl(nullptr, SourceLocation(), nullptr);
 }
 
+ValueDecl *BindingDecl::getDecomposedDecl() const {
+  ExternalASTSource *Source =
+      Decomp.isOffset() ? getASTContext().getExternalSource() : nullptr;
+  return cast_or_null<ValueDecl>(Decomp.get(Source));
+}
+
 VarDecl *BindingDecl::getHoldingVar() const {
   Expr *B = getBinding();
   if (!B)

Modified: cfe/trunk/lib/Sema/SemaExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=361686&r1=361685&r2=361686&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExpr.cpp Fri May 24 18:04:17 2019
@@ -3059,9 +3059,11 @@ ExprResult Sema::BuildDeclarationNameExp
       // FIXME: Support lambda-capture of BindingDecls, once CWG actually
       // decides how that's supposed to work.
       auto *BD = cast<BindingDecl>(VD);
-      if (BD->getDeclContext()->isFunctionOrMethod() &&
-          BD->getDeclContext() != CurContext)
-        diagnoseUncapturableValueReference(*this, Loc, BD, CurContext);
+      if (BD->getDeclContext() != CurContext) {
+        auto *DD = dyn_cast_or_null<VarDecl>(BD->getDecomposedDecl());
+        if (DD && DD->hasLocalStorage())
+          diagnoseUncapturableValueReference(*this, Loc, BD, CurContext);
+      }
       break;
     }
 

Modified: cfe/trunk/lib/Serialization/ASTReaderDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTReaderDecl.cpp?rev=361686&r1=361685&r2=361686&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTReaderDecl.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTReaderDecl.cpp Fri May 24 18:04:17 2019
@@ -1459,8 +1459,10 @@ void ASTDeclReader::VisitParmVarDecl(Par
 void ASTDeclReader::VisitDecompositionDecl(DecompositionDecl *DD) {
   VisitVarDecl(DD);
   auto **BDs = DD->getTrailingObjects<BindingDecl *>();
-  for (unsigned I = 0; I != DD->NumBindings; ++I)
+  for (unsigned I = 0; I != DD->NumBindings; ++I) {
     BDs[I] = ReadDeclAs<BindingDecl>();
+    BDs[I]->setDecomposedDecl(DD);
+  }
 }
 
 void ASTDeclReader::VisitBindingDecl(BindingDecl *BD) {

Modified: cfe/trunk/test/CodeGenCXX/cxx1z-decomposition.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/cxx1z-decomposition.cpp?rev=361686&r1=361685&r2=361686&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenCXX/cxx1z-decomposition.cpp (original)
+++ cfe/trunk/test/CodeGenCXX/cxx1z-decomposition.cpp Fri May 24 18:04:17 2019
@@ -129,7 +129,7 @@ void test_static_simple() {
 }
 
 // CHECK-LABEL: define {{.*}}@_Z17test_static_tuple
-void test_static_tuple() {
+int 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
@@ -162,4 +162,14 @@ void test_static_tuple() {
   // CHECK: store {{.*}}, {{.*}} @_ZGRZ17test_static_tuplevE2x2_
   // CHECK: store {{.*}} @_ZGRZ17test_static_tuplevE2x2_, {{.*}} @_ZZ17test_static_tuplevE2x2
   // CHECK: call void @__cxa_guard_release({{.*}} @_ZGVZ17test_static_tuplevE2x2)
+
+  struct Inner {
+    // CHECK-LABEL: define {{.*}}@_ZZ17test_static_tuplevEN5Inner1fEv(
+    // FIXME: This first load should be constant-folded to the _ZGV... temporary.
+    // CHECK: load {{.*}} @_ZZ17test_static_tuplevE2x2
+    // CHECK: load
+    // CHECK: ret
+    int f() { return x2; }
+  };
+  return Inner().f();
 }

Modified: cfe/trunk/test/SemaCXX/cxx1z-decomposition.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/cxx1z-decomposition.cpp?rev=361686&r1=361685&r2=361686&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/cxx1z-decomposition.cpp (original)
+++ cfe/trunk/test/SemaCXX/cxx1z-decomposition.cpp Fri May 24 18:04:17 2019
@@ -37,14 +37,19 @@ constexpr bool g(S &&s) {
 }
 static_assert(g({1, 2}));
 
+auto [outer1, outer2] = S{1, 2};
 void enclosing() {
-  struct S { int a; };
+  struct S { int a = outer1; };
   auto [n] = S(); // expected-note 2{{'n' declared here}}
 
   struct Q { int f() { return n; } }; // expected-error {{reference to local binding 'n' declared in enclosing function}}
-  // FIXME: This is probably supposed to be valid, but we do not have clear rules on how it's supposed to work.
   (void) [&] { return n; }; // expected-error {{reference to local binding 'n' declared in enclosing function}}
   (void) [n] {}; // expected-error {{'n' in capture list does not name a variable}}
+
+  static auto [m] = S(); // expected-warning {{extension}}
+  struct R { int f() { return m; } };
+  (void) [&] { return m; };
+  (void) [m] {}; // expected-error {{'m' in capture list does not name a variable}}
 }
 
 void bitfield() {




More information about the cfe-commits mailing list