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() { _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits