#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"
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; FIXME: Once support for gcc 4.8 is dropped.
+ TSIPtrPtrTy TSI; // 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() : E(nullptr), TSI(nullptr) {}
+ 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,
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; }
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 {
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);
}