|
@@ -28,6 +28,8 @@
|
|
#include "clang/Basic/TypeTraits.h"
|
|
#include "clang/Basic/TypeTraits.h"
|
|
#include "llvm/ADT/APFloat.h"
|
|
#include "llvm/ADT/APFloat.h"
|
|
#include "llvm/ADT/APSInt.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/SmallVector.h"
|
|
#include "llvm/ADT/StringRef.h"
|
|
#include "llvm/ADT/StringRef.h"
|
|
#include "llvm/Support/AtomicOrdering.h"
|
|
#include "llvm/Support/AtomicOrdering.h"
|
|
@@ -5052,6 +5054,86 @@ class GenericSelectionExpr final
|
|
return getNumAssocs();
|
|
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.
|
|
/// Build a non-result-dependent generic selection expression.
|
|
GenericSelectionExpr(const ASTContext &Context, SourceLocation GenericLoc,
|
|
GenericSelectionExpr(const ASTContext &Context, SourceLocation GenericLoc,
|
|
Expr *ControllingExpr,
|
|
Expr *ControllingExpr,
|
|
@@ -5092,6 +5174,14 @@ public:
|
|
static GenericSelectionExpr *CreateEmpty(const ASTContext &Context,
|
|
static GenericSelectionExpr *CreateEmpty(const ASTContext &Context,
|
|
unsigned NumAssocs);
|
|
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.
|
|
/// The number of association expressions.
|
|
unsigned getNumAssocs() const { return NumAssocs; }
|
|
unsigned getNumAssocs() const { return NumAssocs; }
|
|
|
|
|
|
@@ -5135,23 +5225,43 @@ public:
|
|
return {getTrailingObjects<TypeSourceInfo *>(), 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 {
|
|
SourceLocation getGenericLoc() const {
|