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

llvm-svn: 361686
This commit is contained in:
Richard Smith 2019-05-25 01:04:17 +00:00
parent a846427ad0
commit 0353e5a6cd
6 changed files with 44 additions and 7 deletions

View File

@ -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;

View File

@ -2929,6 +2929,12 @@ BindingDecl *BindingDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
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)

View File

@ -3059,9 +3059,11 @@ ExprResult Sema::BuildDeclarationNameExpr(
// 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;
}

View File

@ -1459,8 +1459,10 @@ void ASTDeclReader::VisitParmVarDecl(ParmVarDecl *PD) {
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) {

View File

@ -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();
}

View File

@ -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() {