diff options
author | Bruno Ricci <riccibrun@gmail.com> | 2019-01-28 14:18:11 +0000 |
---|---|---|
committer | Bruno Ricci <riccibrun@gmail.com> | 2019-01-28 14:18:11 +0000 |
commit | 9feaecf22c235e5b97bd56d657a90fe1736eba56 (patch) | |
tree | 850efde25b4db59058d898c345a273d2341a4bd0 | |
parent | 7b6f874717bedf29413e9c0564433a95453fac61 (diff) | |
download | bcm5719-llvm-9feaecf22c235e5b97bd56d657a90fe1736eba56.tar.gz bcm5719-llvm-9feaecf22c235e5b97bd56d657a90fe1736eba56.zip |
[AST] Introduce GenericSelectionExpr::Association
Introduce a new class GenericSelectionExpr::Association which bundle together
an association expression and its TypeSourceInfo.
An iterator GenericSelectionExpr::AssociationIterator is additionally added to
make it possible to iterate over ranges of Associations. This iterator is a
kind of proxy iterator which abstract over how exactly the expressions and the
TypeSourceInfos are stored.
Differential Revision: https://reviews.llvm.org/D57106
Reviewed By: aaron.ballman
Reviewers: aaron.ballman, steveire, dblaikie, mclow.lists
llvm-svn: 352369
-rw-r--r-- | clang/include/clang/AST/Expr.h | 144 | ||||
-rw-r--r-- | clang/include/clang/AST/RecursiveASTVisitor.h | 8 | ||||
-rw-r--r-- | clang/include/clang/AST/StmtDataCollectors.td | 4 | ||||
-rw-r--r-- | clang/lib/AST/ASTDumper.cpp | 10 | ||||
-rw-r--r-- | clang/lib/AST/StmtPrinter.cpp | 6 | ||||
-rw-r--r-- | clang/lib/AST/StmtProfile.cpp | 7 | ||||
-rw-r--r-- | clang/lib/Sema/SemaExprObjC.cpp | 16 | ||||
-rw-r--r-- | clang/lib/Sema/SemaPseudoObject.cpp | 22 | ||||
-rw-r--r-- | clang/lib/Sema/TreeTransform.h | 11 |
9 files changed, 173 insertions, 55 deletions
diff --git a/clang/include/clang/AST/Expr.h b/clang/include/clang/AST/Expr.h index f770cf327c7..c7b015ab804 100644 --- a/clang/include/clang/AST/Expr.h +++ b/clang/include/clang/AST/Expr.h @@ -28,6 +28,8 @@ #include "clang/Basic/TypeTraits.h" #include "llvm/ADT/APFloat.h" #include "llvm/ADT/APSInt.h" +#include "llvm/ADT/iterator.h" +#include "llvm/ADT/iterator_range.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/AtomicOrdering.h" @@ -5052,6 +5054,86 @@ class GenericSelectionExpr final return getNumAssocs(); } + template <bool Const> class AssociationIteratorTy; + /// Bundle together an association expression and its TypeSourceInfo. + /// The Const template parameter is for the const and non-const versions + /// of AssociationTy. + template <bool Const> class AssociationTy { + friend class GenericSelectionExpr; + template <bool OtherConst> friend class AssociationIteratorTy; + using ExprPtrTy = + typename std::conditional<Const, const Expr *, Expr *>::type; + using TSIPtrTy = typename std::conditional<Const, const TypeSourceInfo *, + TypeSourceInfo *>::type; + ExprPtrTy E; + TSIPtrTy TSI; + bool Selected; + AssociationTy(ExprPtrTy E, TSIPtrTy TSI, bool Selected) + : E(E), TSI(TSI), Selected(Selected) {} + + public: + ExprPtrTy getAssociationExpr() const { return E; } + TSIPtrTy getTypeSourceInfo() const { return TSI; } + QualType getType() const { return TSI ? TSI->getType() : QualType(); } + bool isSelected() const { return Selected; } + AssociationTy *operator->() { return this; } + const AssociationTy *operator->() const { return this; } + }; // class AssociationTy + + /// Iterator over const and non-const Association objects. The Association + /// objects are created on the fly when the iterator is dereferenced. + /// This abstract over how exactly the association expressions and the + /// corresponding TypeSourceInfo * are stored. + template <bool Const> + class AssociationIteratorTy + : public llvm::iterator_facade_base< + AssociationIteratorTy<Const>, std::input_iterator_tag, + AssociationTy<Const>, std::ptrdiff_t, AssociationTy<Const>, + AssociationTy<Const>> { + friend class GenericSelectionExpr; + // FIXME: This iterator could conceptually be a random access iterator, and + // it would be nice if we could strengthen the iterator category someday. + // However this iterator does not satisfy two requirements of forward + // iterators: + // a) reference = T& or reference = const T& + // b) If It1 and It2 are both dereferenceable, then It1 == It2 if and only + // if *It1 and *It2 are bound to the same objects. + // An alternative design approach was discussed during review; + // store an Association object inside the iterator, and return a reference + // to it when dereferenced. This idea was discarded beacuse of nasty + // lifetime issues: + // AssociationIterator It = ...; + // const Association &Assoc = *It++; // Oops, Assoc is dangling. + using BaseTy = typename AssociationIteratorTy::iterator_facade_base; + using StmtPtrPtrTy = + typename std::conditional<Const, const Stmt *const *, Stmt **>::type; + using TSIPtrPtrTy = + typename std::conditional<Const, const TypeSourceInfo *const *, + TypeSourceInfo **>::type; + StmtPtrPtrTy E = nullptr; + TSIPtrPtrTy TSI = nullptr; // Kept in sync with E. + unsigned Offset = 0, SelectedOffset = 0; + AssociationIteratorTy(StmtPtrPtrTy E, TSIPtrPtrTy TSI, unsigned Offset, + unsigned SelectedOffset) + : E(E), TSI(TSI), Offset(Offset), SelectedOffset(SelectedOffset) {} + + public: + AssociationIteratorTy() = default; + typename BaseTy::reference operator*() const { + return AssociationTy<Const>(cast<Expr>(*E), *TSI, + Offset == SelectedOffset); + } + typename BaseTy::pointer operator->() const { return **this; } + using BaseTy::operator++; + AssociationIteratorTy &operator++() { + ++E; + ++TSI; + ++Offset; + return *this; + } + bool operator==(AssociationIteratorTy Other) const { return E == Other.E; } + }; // class AssociationIterator + /// Build a non-result-dependent generic selection expression. GenericSelectionExpr(const ASTContext &Context, SourceLocation GenericLoc, Expr *ControllingExpr, @@ -5092,6 +5174,14 @@ public: static GenericSelectionExpr *CreateEmpty(const ASTContext &Context, unsigned NumAssocs); + using Association = AssociationTy<false>; + using ConstAssociation = AssociationTy<true>; + using AssociationIterator = AssociationIteratorTy<false>; + using ConstAssociationIterator = AssociationIteratorTy<true>; + using association_range = llvm::iterator_range<AssociationIterator>; + using const_association_range = + llvm::iterator_range<ConstAssociationIterator>; + /// The number of association expressions. unsigned getNumAssocs() const { return NumAssocs; } @@ -5135,23 +5225,43 @@ public: return {getTrailingObjects<TypeSourceInfo *>(), NumAssocs}; } - Expr *getAssocExpr(unsigned i) { - return cast<Expr>(getTrailingObjects<Stmt *>()[AssocExprStartIndex + i]); - } - const Expr *getAssocExpr(unsigned i) const { - return cast<Expr>(getTrailingObjects<Stmt *>()[AssocExprStartIndex + i]); - } - - TypeSourceInfo *getAssocTypeSourceInfo(unsigned i) { - return getTrailingObjects<TypeSourceInfo *>()[i]; - } - const TypeSourceInfo *getAssocTypeSourceInfo(unsigned i) const { - return getTrailingObjects<TypeSourceInfo *>()[i]; - } - - QualType getAssocType(unsigned i) const { - const TypeSourceInfo *TSI = getAssocTypeSourceInfo(i); - return TSI ? TSI->getType() : QualType(); + /// Return the Ith association expression with its TypeSourceInfo, + /// bundled together in GenericSelectionExpr::(Const)Association. + Association getAssociation(unsigned I) { + assert(I < getNumAssocs() && + "Out-of-range index in GenericSelectionExpr::getAssociation!"); + return Association( + cast<Expr>(getTrailingObjects<Stmt *>()[AssocExprStartIndex + I]), + getTrailingObjects<TypeSourceInfo *>()[I], + !isResultDependent() && (getResultIndex() == I)); + } + ConstAssociation getAssociation(unsigned I) const { + assert(I < getNumAssocs() && + "Out-of-range index in GenericSelectionExpr::getAssociation!"); + return ConstAssociation( + cast<Expr>(getTrailingObjects<Stmt *>()[AssocExprStartIndex + I]), + getTrailingObjects<TypeSourceInfo *>()[I], + !isResultDependent() && (getResultIndex() == I)); + } + + association_range associations() { + AssociationIterator Begin(getTrailingObjects<Stmt *>() + + AssocExprStartIndex, + getTrailingObjects<TypeSourceInfo *>(), + /*Offset=*/0, ResultIndex); + AssociationIterator End(Begin.E + NumAssocs, Begin.TSI + NumAssocs, + /*Offset=*/NumAssocs, ResultIndex); + return llvm::make_range(Begin, End); + } + + const_association_range associations() const { + ConstAssociationIterator Begin(getTrailingObjects<Stmt *>() + + AssocExprStartIndex, + getTrailingObjects<TypeSourceInfo *>(), + /*Offset=*/0, ResultIndex); + ConstAssociationIterator End(Begin.E + NumAssocs, Begin.TSI + NumAssocs, + /*Offset=*/NumAssocs, ResultIndex); + return llvm::make_range(Begin, End); } SourceLocation getGenericLoc() const { diff --git a/clang/include/clang/AST/RecursiveASTVisitor.h b/clang/include/clang/AST/RecursiveASTVisitor.h index 957b5493344..41892a0d7fd 100644 --- a/clang/include/clang/AST/RecursiveASTVisitor.h +++ b/clang/include/clang/AST/RecursiveASTVisitor.h @@ -2300,10 +2300,10 @@ bool RecursiveASTVisitor<Derived>::TraverseInitListExpr( // generic associations). DEF_TRAVERSE_STMT(GenericSelectionExpr, { TRY_TO(TraverseStmt(S->getControllingExpr())); - for (unsigned i = 0; i != S->getNumAssocs(); ++i) { - if (TypeSourceInfo *TS = S->getAssocTypeSourceInfo(i)) - TRY_TO(TraverseTypeLoc(TS->getTypeLoc())); - TRY_TO_TRAVERSE_OR_ENQUEUE_STMT(S->getAssocExpr(i)); + for (const GenericSelectionExpr::Association &Assoc : S->associations()) { + if (TypeSourceInfo *TSI = Assoc.getTypeSourceInfo()) + TRY_TO(TraverseTypeLoc(TSI->getTypeLoc())); + TRY_TO_TRAVERSE_OR_ENQUEUE_STMT(Assoc.getAssociationExpr()); } ShouldVisitChildren = false; }) diff --git a/clang/include/clang/AST/StmtDataCollectors.td b/clang/include/clang/AST/StmtDataCollectors.td index 90ca0802733..a46d2714eb4 100644 --- a/clang/include/clang/AST/StmtDataCollectors.td +++ b/clang/include/clang/AST/StmtDataCollectors.td @@ -189,8 +189,8 @@ class CXXFoldExpr { } class GenericSelectionExpr { code Code = [{ - for (unsigned i = 0; i < S->getNumAssocs(); ++i) { - addData(S->getAssocType(i)); + for (const GenericSelectionExpr::ConstAssociation &Assoc : S->associations()) { + addData(Assoc.getType()); } }]; } diff --git a/clang/lib/AST/ASTDumper.cpp b/clang/lib/AST/ASTDumper.cpp index b91dab5aa38..5c99dab356f 100644 --- a/clang/lib/AST/ASTDumper.cpp +++ b/clang/lib/AST/ASTDumper.cpp @@ -1462,21 +1462,21 @@ void ASTDumper::VisitGenericSelectionExpr(const GenericSelectionExpr *E) { dumpStmt(E->getControllingExpr()); dumpTypeAsChild(E->getControllingExpr()->getType()); // FIXME: remove - for (unsigned I = 0, N = E->getNumAssocs(); I != N; ++I) { + for (const auto &Assoc : E->associations()) { dumpChild([=] { - if (const TypeSourceInfo *TSI = E->getAssocTypeSourceInfo(I)) { + if (const TypeSourceInfo *TSI = Assoc.getTypeSourceInfo()) { OS << "case "; NodeDumper.dumpType(TSI->getType()); } else { OS << "default"; } - if (!E->isResultDependent() && E->getResultIndex() == I) + if (Assoc.isSelected()) OS << " selected"; - if (const TypeSourceInfo *TSI = E->getAssocTypeSourceInfo(I)) + if (const TypeSourceInfo *TSI = Assoc.getTypeSourceInfo()) dumpTypeAsChild(TSI->getType()); - dumpStmt(E->getAssocExpr(I)); + dumpStmt(Assoc.getAssociationExpr()); }); } } diff --git a/clang/lib/AST/StmtPrinter.cpp b/clang/lib/AST/StmtPrinter.cpp index 221d134d338..acf19aaaf41 100644 --- a/clang/lib/AST/StmtPrinter.cpp +++ b/clang/lib/AST/StmtPrinter.cpp @@ -1261,15 +1261,15 @@ void StmtPrinter::VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *Node){ void StmtPrinter::VisitGenericSelectionExpr(GenericSelectionExpr *Node) { OS << "_Generic("; PrintExpr(Node->getControllingExpr()); - for (unsigned i = 0; i != Node->getNumAssocs(); ++i) { + for (const GenericSelectionExpr::Association &Assoc : Node->associations()) { OS << ", "; - QualType T = Node->getAssocType(i); + QualType T = Assoc.getType(); if (T.isNull()) OS << "default"; else T.print(OS, Policy); OS << ": "; - PrintExpr(Node->getAssocExpr(i)); + PrintExpr(Assoc.getAssociationExpr()); } OS << ")"; } diff --git a/clang/lib/AST/StmtProfile.cpp b/clang/lib/AST/StmtProfile.cpp index 8f8de61f34f..c064ea90a26 100644 --- a/clang/lib/AST/StmtProfile.cpp +++ b/clang/lib/AST/StmtProfile.cpp @@ -1259,13 +1259,14 @@ void StmtProfiler::VisitBlockExpr(const BlockExpr *S) { void StmtProfiler::VisitGenericSelectionExpr(const GenericSelectionExpr *S) { VisitExpr(S); - for (unsigned i = 0; i != S->getNumAssocs(); ++i) { - QualType T = S->getAssocType(i); + for (const GenericSelectionExpr::ConstAssociation &Assoc : + S->associations()) { + QualType T = Assoc.getType(); if (T.isNull()) ID.AddPointer(nullptr); else VisitType(T); - VisitExpr(S->getAssocExpr(i)); + VisitExpr(Assoc.getAssociationExpr()); } } diff --git a/clang/lib/Sema/SemaExprObjC.cpp b/clang/lib/Sema/SemaExprObjC.cpp index 4ca3b851c18..fdb59874cc9 100644 --- a/clang/lib/Sema/SemaExprObjC.cpp +++ b/clang/lib/Sema/SemaExprObjC.cpp @@ -4332,14 +4332,16 @@ Expr *Sema::stripARCUnbridgedCast(Expr *e) { assert(!gse->isResultDependent()); unsigned n = gse->getNumAssocs(); - SmallVector<Expr*, 4> subExprs(n); - SmallVector<TypeSourceInfo*, 4> subTypes(n); - for (unsigned i = 0; i != n; ++i) { - subTypes[i] = gse->getAssocTypeSourceInfo(i); - Expr *sub = gse->getAssocExpr(i); - if (i == gse->getResultIndex()) + SmallVector<Expr *, 4> subExprs; + SmallVector<TypeSourceInfo *, 4> subTypes; + subExprs.reserve(n); + subTypes.reserve(n); + for (const GenericSelectionExpr::Association &assoc : gse->associations()) { + subTypes.push_back(assoc.getTypeSourceInfo()); + Expr *sub = assoc.getAssociationExpr(); + if (assoc.isSelected()) sub = stripARCUnbridgedCast(sub); - subExprs[i] = sub; + subExprs.push_back(sub); } return GenericSelectionExpr::Create( diff --git a/clang/lib/Sema/SemaPseudoObject.cpp b/clang/lib/Sema/SemaPseudoObject.cpp index 37dd7b1e8d2..28a4d62b03e 100644 --- a/clang/lib/Sema/SemaPseudoObject.cpp +++ b/clang/lib/Sema/SemaPseudoObject.cpp @@ -140,19 +140,23 @@ namespace { unsigned resultIndex = gse->getResultIndex(); unsigned numAssocs = gse->getNumAssocs(); - SmallVector<Expr*, 8> assocs(numAssocs); - SmallVector<TypeSourceInfo*, 8> assocTypes(numAssocs); - - for (unsigned i = 0; i != numAssocs; ++i) { - Expr *assoc = gse->getAssocExpr(i); - if (i == resultIndex) assoc = rebuild(assoc); - assocs[i] = assoc; - assocTypes[i] = gse->getAssocTypeSourceInfo(i); + SmallVector<Expr *, 8> assocExprs; + SmallVector<TypeSourceInfo *, 8> assocTypes; + assocExprs.reserve(numAssocs); + assocTypes.reserve(numAssocs); + + for (const GenericSelectionExpr::Association &assoc : + gse->associations()) { + Expr *assocExpr = assoc.getAssociationExpr(); + if (assoc.isSelected()) + assocExpr = rebuild(assocExpr); + assocExprs.push_back(assocExpr); + assocTypes.push_back(assoc.getTypeSourceInfo()); } return GenericSelectionExpr::Create( S.Context, gse->getGenericLoc(), gse->getControllingExpr(), - assocTypes, assocs, gse->getDefaultLoc(), gse->getRParenLoc(), + assocTypes, assocExprs, gse->getDefaultLoc(), gse->getRParenLoc(), gse->containsUnexpandedParameterPack(), resultIndex); } diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index 389031d491a..2e434a3c0e3 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -9071,10 +9071,10 @@ TreeTransform<Derived>::TransformGenericSelectionExpr(GenericSelectionExpr *E) { SmallVector<Expr *, 4> AssocExprs; SmallVector<TypeSourceInfo *, 4> AssocTypes; - for (unsigned i = 0; i != E->getNumAssocs(); ++i) { - TypeSourceInfo *TS = E->getAssocTypeSourceInfo(i); - if (TS) { - TypeSourceInfo *AssocType = getDerived().TransformType(TS); + for (const GenericSelectionExpr::Association &Assoc : E->associations()) { + TypeSourceInfo *TSI = Assoc.getTypeSourceInfo(); + if (TSI) { + TypeSourceInfo *AssocType = getDerived().TransformType(TSI); if (!AssocType) return ExprError(); AssocTypes.push_back(AssocType); @@ -9082,7 +9082,8 @@ TreeTransform<Derived>::TransformGenericSelectionExpr(GenericSelectionExpr *E) { AssocTypes.push_back(nullptr); } - ExprResult AssocExpr = getDerived().TransformExpr(E->getAssocExpr(i)); + ExprResult AssocExpr = + getDerived().TransformExpr(Assoc.getAssociationExpr()); if (AssocExpr.isInvalid()) return ExprError(); AssocExprs.push_back(AssocExpr.get()); |