class CXXFinalOverriderMap;
class CXXIndirectPrimaryBaseSet;
class CXXMethodDecl;
+class DecompositionDecl;
class DiagnosticBuilder;
class FriendDecl;
class FunctionTemplateDecl;
/// 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
/// 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;
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; }
};
NumBindings(Bindings.size()) {
std::uninitialized_copy(Bindings.begin(), Bindings.end(),
getTrailingObjects<BindingDecl *>());
+ for (auto *B : Bindings)
+ B->setDecomposedDecl(this);
}
void anchor() override;
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)
// 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;
}
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) {
}
// 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
// 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();
}
}
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() {