@@ -1475,6 +1475,48 @@ static DeclAccessPair findDecomposableBaseClass(Sema &S, SourceLocation Loc,
14751475 return DeclAccessPair::make(const_cast<CXXRecordDecl*>(ClassWithFields), AS);
14761476}
14771477
1478+ static bool CheckMemberDecompositionFields(Sema &S, SourceLocation Loc,
1479+ const CXXRecordDecl *OrigRD,
1480+ QualType DecompType,
1481+ DeclAccessPair BasePair) {
1482+ const CXXRecordDecl *RD = cast_or_null<CXXRecordDecl>(BasePair.getDecl());
1483+ if (!RD)
1484+ return true;
1485+
1486+ for (auto *FD : RD->fields()) {
1487+ if (FD->isUnnamedBitField())
1488+ continue;
1489+
1490+ // All the non-static data members are required to be nameable, so they
1491+ // must all have names.
1492+ if (!FD->getDeclName()) {
1493+ if (RD->isLambda()) {
1494+ S.Diag(Loc, diag::err_decomp_decl_lambda);
1495+ S.Diag(RD->getLocation(), diag::note_lambda_decl);
1496+ return true;
1497+ }
1498+
1499+ if (FD->isAnonymousStructOrUnion()) {
1500+ S.Diag(Loc, diag::err_decomp_decl_anon_union_member)
1501+ << DecompType << FD->getType()->isUnionType();
1502+ S.Diag(FD->getLocation(), diag::note_declared_at);
1503+ return true;
1504+ }
1505+
1506+ // FIXME: Are there any other ways we could have an anonymous member?
1507+ }
1508+ // The field must be accessible in the context of the structured binding.
1509+ // We already checked that the base class is accessible.
1510+ // FIXME: Add 'const' to AccessedEntity's classes so we can remove the
1511+ // const_cast here.
1512+ S.CheckStructuredBindingMemberAccess(
1513+ Loc, const_cast<CXXRecordDecl *>(OrigRD),
1514+ DeclAccessPair::make(FD, CXXRecordDecl::MergeAccess(
1515+ BasePair.getAccess(), FD->getAccess())));
1516+ }
1517+ return false;
1518+ }
1519+
14781520static bool checkMemberDecomposition(Sema &S, ArrayRef<BindingDecl*> Bindings,
14791521 ValueDecl *Src, QualType DecompType,
14801522 const CXXRecordDecl *OrigRD) {
@@ -1503,43 +1545,20 @@ static bool checkMemberDecomposition(Sema &S, ArrayRef<BindingDecl*> Bindings,
15031545 auto FlatBindings = DD->flat_bindings();
15041546 assert(llvm::range_size(FlatBindings) == NumFields);
15051547 auto FlatBindingsItr = FlatBindings.begin();
1548+
1549+ if (CheckMemberDecompositionFields(S, Src->getLocation(), OrigRD, DecompType,
1550+ BasePair))
1551+ return true;
1552+
15061553 for (auto *FD : RD->fields()) {
15071554 if (FD->isUnnamedBitField())
15081555 continue;
15091556
1510- // All the non-static data members are required to be nameable, so they
1511- // must all have names.
1512- if (!FD->getDeclName()) {
1513- if (RD->isLambda()) {
1514- S.Diag(Src->getLocation(), diag::err_decomp_decl_lambda);
1515- S.Diag(RD->getLocation(), diag::note_lambda_decl);
1516- return true;
1517- }
1518-
1519- if (FD->isAnonymousStructOrUnion()) {
1520- S.Diag(Src->getLocation(), diag::err_decomp_decl_anon_union_member)
1521- << DecompType << FD->getType()->isUnionType();
1522- S.Diag(FD->getLocation(), diag::note_declared_at);
1523- return true;
1524- }
1525-
1526- // FIXME: Are there any other ways we could have an anonymous member?
1527- }
1528-
15291557 // We have a real field to bind.
15301558 assert(FlatBindingsItr != FlatBindings.end());
15311559 BindingDecl *B = *(FlatBindingsItr++);
15321560 SourceLocation Loc = B->getLocation();
15331561
1534- // The field must be accessible in the context of the structured binding.
1535- // We already checked that the base class is accessible.
1536- // FIXME: Add 'const' to AccessedEntity's classes so we can remove the
1537- // const_cast here.
1538- S.CheckStructuredBindingMemberAccess(
1539- Loc, const_cast<CXXRecordDecl *>(OrigRD),
1540- DeclAccessPair::make(FD, CXXRecordDecl::MergeAccess(
1541- BasePair.getAccess(), FD->getAccess())));
1542-
15431562 // Initialize the binding to Src.FD.
15441563 ExprResult E = S.BuildDeclRefExpr(Src, DecompType, VK_LValue, Loc);
15451564 if (E.isInvalid())
@@ -1642,6 +1661,50 @@ void Sema::CheckCompleteDecompositionDeclaration(DecompositionDecl *DD) {
16421661 DD->setInvalidDecl();
16431662}
16441663
1664+ std::optional<unsigned> Sema::GetDecompositionElementCount(QualType T,
1665+ SourceLocation Loc) {
1666+ const ASTContext &Ctx = getASTContext();
1667+ assert(!T->isDependentType());
1668+ if (auto *CAT = Ctx.getAsConstantArrayType(T))
1669+ return CAT->getSize().getZExtValue();
1670+ if (auto *VT = T->getAs<VectorType>())
1671+ return VT->getNumElements();
1672+ if (T->getAs<ComplexType>())
1673+ return 2;
1674+
1675+ llvm::APSInt TupleSize(Ctx.getTypeSize(Ctx.getSizeType()));
1676+ switch (isTupleLike(*this, Loc, T, TupleSize)) {
1677+ case IsTupleLike::Error:
1678+ return {};
1679+ case IsTupleLike::TupleLike:
1680+ return TupleSize.getExtValue();
1681+ case IsTupleLike::NotTupleLike:
1682+ break;
1683+ }
1684+ CXXRecordDecl *OrigRD = T->getAsCXXRecordDecl();
1685+ if (!OrigRD || OrigRD->isUnion()) {
1686+ return std::nullopt;
1687+ }
1688+
1689+ if (RequireCompleteType(Loc, T, diag::err_incomplete_type))
1690+ return std::nullopt;
1691+
1692+ CXXCastPath BasePath;
1693+ DeclAccessPair BasePair =
1694+ findDecomposableBaseClass(*this, Loc, OrigRD, BasePath);
1695+ const CXXRecordDecl *RD = cast_or_null<CXXRecordDecl>(BasePair.getDecl());
1696+ if (!RD)
1697+ return std::nullopt;
1698+
1699+ unsigned NumFields = llvm::count_if(
1700+ RD->fields(), [](FieldDecl *FD) { return !FD->isUnnamedBitField(); });
1701+
1702+ if (CheckMemberDecompositionFields(*this, Loc, OrigRD, T, BasePair))
1703+ return true;
1704+
1705+ return NumFields;
1706+ }
1707+
16451708void Sema::MergeVarDeclExceptionSpecs(VarDecl *New, VarDecl *Old) {
16461709 // Shortcut if exceptions are disabled.
16471710 if (!getLangOpts().CXXExceptions)
@@ -17262,8 +17325,8 @@ void Sema::DiagnoseStaticAssertDetails(const Expr *E) {
1726217325 Expr::EvalResult Result;
1726317326 SmallString<12> ValueString;
1726417327 bool Print;
17265- } DiagSide[2] = {{LHS , Expr::EvalResult(), {}, false},
17266- {RHS , Expr::EvalResult(), {}, false}};
17328+ } DiagSide[2] = {{Op->getLHS() , Expr::EvalResult(), {}, false},
17329+ {Op->getRHS() , Expr::EvalResult(), {}, false}};
1726717330 for (unsigned I = 0; I < 2; I++) {
1726817331 const Expr *Side = DiagSide[I].Cond;
1726917332
0 commit comments