forked from OSchip/llvm-project
Permit static local structured bindings to be named from arbitrary scopes inside their declaring scope.
llvm-svn: 361686
This commit is contained in:
parent
a846427ad0
commit
0353e5a6cd
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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() {
|
||||
|
|
Loading…
Reference in New Issue