Re-commit "[AST] Introduce GenericSelectionExpr::Association"

This time with a fix to make gcc 4.8 happy.

llvm-svn: 352486
This commit is contained in:
Bruno Ricci 2019-01-29 12:57:11 +00:00
parent e30d87ecea
commit 1ec7fd35ce
9 changed files with 167 additions and 49 deletions

View File

@ -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; 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. /// 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 the Ith association expression with its TypeSourceInfo,
return cast<Expr>(getTrailingObjects<Stmt *>()[AssocExprStartIndex + i]); /// 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));
} }
const Expr *getAssocExpr(unsigned i) const { ConstAssociation getAssociation(unsigned I) const {
return cast<Expr>(getTrailingObjects<Stmt *>()[AssocExprStartIndex + i]); assert(I < getNumAssocs() &&
"Out-of-range index in GenericSelectionExpr::getAssociation!");
return ConstAssociation(
cast<Expr>(getTrailingObjects<Stmt *>()[AssocExprStartIndex + I]),
getTrailingObjects<TypeSourceInfo *>()[I],
!isResultDependent() && (getResultIndex() == I));
} }
TypeSourceInfo *getAssocTypeSourceInfo(unsigned i) { association_range associations() {
return getTrailingObjects<TypeSourceInfo *>()[i]; AssociationIterator Begin(getTrailingObjects<Stmt *>() +
} AssocExprStartIndex,
const TypeSourceInfo *getAssocTypeSourceInfo(unsigned i) const { getTrailingObjects<TypeSourceInfo *>(),
return getTrailingObjects<TypeSourceInfo *>()[i]; /*Offset=*/0, ResultIndex);
AssociationIterator End(Begin.E + NumAssocs, Begin.TSI + NumAssocs,
/*Offset=*/NumAssocs, ResultIndex);
return llvm::make_range(Begin, End);
} }
QualType getAssocType(unsigned i) const { const_association_range associations() const {
const TypeSourceInfo *TSI = getAssocTypeSourceInfo(i); ConstAssociationIterator Begin(getTrailingObjects<Stmt *>() +
return TSI ? TSI->getType() : QualType(); 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 {

View File

@ -2301,10 +2301,10 @@ bool RecursiveASTVisitor<Derived>::TraverseInitListExpr(
// generic associations). // generic associations).
DEF_TRAVERSE_STMT(GenericSelectionExpr, { DEF_TRAVERSE_STMT(GenericSelectionExpr, {
TRY_TO(TraverseStmt(S->getControllingExpr())); TRY_TO(TraverseStmt(S->getControllingExpr()));
for (unsigned i = 0; i != S->getNumAssocs(); ++i) { for (const GenericSelectionExpr::Association &Assoc : S->associations()) {
if (TypeSourceInfo *TS = S->getAssocTypeSourceInfo(i)) if (TypeSourceInfo *TSI = Assoc.getTypeSourceInfo())
TRY_TO(TraverseTypeLoc(TS->getTypeLoc())); TRY_TO(TraverseTypeLoc(TSI->getTypeLoc()));
TRY_TO_TRAVERSE_OR_ENQUEUE_STMT(S->getAssocExpr(i)); TRY_TO_TRAVERSE_OR_ENQUEUE_STMT(Assoc.getAssociationExpr());
} }
ShouldVisitChildren = false; ShouldVisitChildren = false;
}) })

View File

@ -189,8 +189,8 @@ class CXXFoldExpr {
} }
class GenericSelectionExpr { class GenericSelectionExpr {
code Code = [{ code Code = [{
for (unsigned i = 0; i < S->getNumAssocs(); ++i) { for (const GenericSelectionExpr::ConstAssociation &Assoc : S->associations()) {
addData(S->getAssocType(i)); addData(Assoc.getType());
} }
}]; }];
} }

View File

@ -1462,21 +1462,21 @@ void ASTDumper::VisitGenericSelectionExpr(const GenericSelectionExpr *E) {
dumpStmt(E->getControllingExpr()); dumpStmt(E->getControllingExpr());
dumpTypeAsChild(E->getControllingExpr()->getType()); // FIXME: remove dumpTypeAsChild(E->getControllingExpr()->getType()); // FIXME: remove
for (unsigned I = 0, N = E->getNumAssocs(); I != N; ++I) { for (const auto &Assoc : E->associations()) {
dumpChild([=] { dumpChild([=] {
if (const TypeSourceInfo *TSI = E->getAssocTypeSourceInfo(I)) { if (const TypeSourceInfo *TSI = Assoc.getTypeSourceInfo()) {
OS << "case "; OS << "case ";
NodeDumper.dumpType(TSI->getType()); NodeDumper.dumpType(TSI->getType());
} else { } else {
OS << "default"; OS << "default";
} }
if (!E->isResultDependent() && E->getResultIndex() == I) if (Assoc.isSelected())
OS << " selected"; OS << " selected";
if (const TypeSourceInfo *TSI = E->getAssocTypeSourceInfo(I)) if (const TypeSourceInfo *TSI = Assoc.getTypeSourceInfo())
dumpTypeAsChild(TSI->getType()); dumpTypeAsChild(TSI->getType());
dumpStmt(E->getAssocExpr(I)); dumpStmt(Assoc.getAssociationExpr());
}); });
} }
} }

View File

@ -1261,15 +1261,15 @@ void StmtPrinter::VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *Node){
void StmtPrinter::VisitGenericSelectionExpr(GenericSelectionExpr *Node) { void StmtPrinter::VisitGenericSelectionExpr(GenericSelectionExpr *Node) {
OS << "_Generic("; OS << "_Generic(";
PrintExpr(Node->getControllingExpr()); PrintExpr(Node->getControllingExpr());
for (unsigned i = 0; i != Node->getNumAssocs(); ++i) { for (const GenericSelectionExpr::Association &Assoc : Node->associations()) {
OS << ", "; OS << ", ";
QualType T = Node->getAssocType(i); QualType T = Assoc.getType();
if (T.isNull()) if (T.isNull())
OS << "default"; OS << "default";
else else
T.print(OS, Policy); T.print(OS, Policy);
OS << ": "; OS << ": ";
PrintExpr(Node->getAssocExpr(i)); PrintExpr(Assoc.getAssociationExpr());
} }
OS << ")"; OS << ")";
} }

View File

@ -1260,13 +1260,14 @@ void StmtProfiler::VisitBlockExpr(const BlockExpr *S) {
void StmtProfiler::VisitGenericSelectionExpr(const GenericSelectionExpr *S) { void StmtProfiler::VisitGenericSelectionExpr(const GenericSelectionExpr *S) {
VisitExpr(S); VisitExpr(S);
for (unsigned i = 0; i != S->getNumAssocs(); ++i) { for (const GenericSelectionExpr::ConstAssociation &Assoc :
QualType T = S->getAssocType(i); S->associations()) {
QualType T = Assoc.getType();
if (T.isNull()) if (T.isNull())
ID.AddPointer(nullptr); ID.AddPointer(nullptr);
else else
VisitType(T); VisitType(T);
VisitExpr(S->getAssocExpr(i)); VisitExpr(Assoc.getAssociationExpr());
} }
} }

View File

@ -4332,14 +4332,16 @@ Expr *Sema::stripARCUnbridgedCast(Expr *e) {
assert(!gse->isResultDependent()); assert(!gse->isResultDependent());
unsigned n = gse->getNumAssocs(); unsigned n = gse->getNumAssocs();
SmallVector<Expr*, 4> subExprs(n); SmallVector<Expr *, 4> subExprs;
SmallVector<TypeSourceInfo*, 4> subTypes(n); SmallVector<TypeSourceInfo *, 4> subTypes;
for (unsigned i = 0; i != n; ++i) { subExprs.reserve(n);
subTypes[i] = gse->getAssocTypeSourceInfo(i); subTypes.reserve(n);
Expr *sub = gse->getAssocExpr(i); for (const GenericSelectionExpr::Association &assoc : gse->associations()) {
if (i == gse->getResultIndex()) subTypes.push_back(assoc.getTypeSourceInfo());
Expr *sub = assoc.getAssociationExpr();
if (assoc.isSelected())
sub = stripARCUnbridgedCast(sub); sub = stripARCUnbridgedCast(sub);
subExprs[i] = sub; subExprs.push_back(sub);
} }
return GenericSelectionExpr::Create( return GenericSelectionExpr::Create(

View File

@ -140,19 +140,23 @@ namespace {
unsigned resultIndex = gse->getResultIndex(); unsigned resultIndex = gse->getResultIndex();
unsigned numAssocs = gse->getNumAssocs(); unsigned numAssocs = gse->getNumAssocs();
SmallVector<Expr*, 8> assocs(numAssocs); SmallVector<Expr *, 8> assocExprs;
SmallVector<TypeSourceInfo*, 8> assocTypes(numAssocs); SmallVector<TypeSourceInfo *, 8> assocTypes;
assocExprs.reserve(numAssocs);
assocTypes.reserve(numAssocs);
for (unsigned i = 0; i != numAssocs; ++i) { for (const GenericSelectionExpr::Association &assoc :
Expr *assoc = gse->getAssocExpr(i); gse->associations()) {
if (i == resultIndex) assoc = rebuild(assoc); Expr *assocExpr = assoc.getAssociationExpr();
assocs[i] = assoc; if (assoc.isSelected())
assocTypes[i] = gse->getAssocTypeSourceInfo(i); assocExpr = rebuild(assocExpr);
assocExprs.push_back(assocExpr);
assocTypes.push_back(assoc.getTypeSourceInfo());
} }
return GenericSelectionExpr::Create( return GenericSelectionExpr::Create(
S.Context, gse->getGenericLoc(), gse->getControllingExpr(), S.Context, gse->getGenericLoc(), gse->getControllingExpr(),
assocTypes, assocs, gse->getDefaultLoc(), gse->getRParenLoc(), assocTypes, assocExprs, gse->getDefaultLoc(), gse->getRParenLoc(),
gse->containsUnexpandedParameterPack(), resultIndex); gse->containsUnexpandedParameterPack(), resultIndex);
} }

View File

@ -9073,10 +9073,10 @@ TreeTransform<Derived>::TransformGenericSelectionExpr(GenericSelectionExpr *E) {
SmallVector<Expr *, 4> AssocExprs; SmallVector<Expr *, 4> AssocExprs;
SmallVector<TypeSourceInfo *, 4> AssocTypes; SmallVector<TypeSourceInfo *, 4> AssocTypes;
for (unsigned i = 0; i != E->getNumAssocs(); ++i) { for (const GenericSelectionExpr::Association &Assoc : E->associations()) {
TypeSourceInfo *TS = E->getAssocTypeSourceInfo(i); TypeSourceInfo *TSI = Assoc.getTypeSourceInfo();
if (TS) { if (TSI) {
TypeSourceInfo *AssocType = getDerived().TransformType(TS); TypeSourceInfo *AssocType = getDerived().TransformType(TSI);
if (!AssocType) if (!AssocType)
return ExprError(); return ExprError();
AssocTypes.push_back(AssocType); AssocTypes.push_back(AssocType);
@ -9084,7 +9084,8 @@ TreeTransform<Derived>::TransformGenericSelectionExpr(GenericSelectionExpr *E) {
AssocTypes.push_back(nullptr); AssocTypes.push_back(nullptr);
} }
ExprResult AssocExpr = getDerived().TransformExpr(E->getAssocExpr(i)); ExprResult AssocExpr =
getDerived().TransformExpr(Assoc.getAssociationExpr());
if (AssocExpr.isInvalid()) if (AssocExpr.isInvalid())
return ExprError(); return ExprError();
AssocExprs.push_back(AssocExpr.get()); AssocExprs.push_back(AssocExpr.get());