Hi all,
the current Clang implementation has a specific_attr_iterator<AttrType>
that allows iterating over the attributes of a certain type (all
attributes are kept in a single llvm::SmallVector), but it lacks a
reverse iterator. This patch adds this functionality.
Why is this useful/needed (in the short run).
-----------------------------------------------------------
The C++11 standard allows attributes to appertain to types and portions
of the declarator, e.g.:
int[[attr1] *[[attr2] *[[attr3] var;
However, Clang is still collapsing those attributes on the declaration
itself:
int **var [[attr1,attr2,attr3]].
According to C++11 when multiple attributes of the same kind appertain
to the same "node", their order is irrelevant (note that these
attributes may have different attribute parameters):
int var [[attrA("x"), attrA("y")]]
and
int var [[attrA("y"), attrA("x")]]
must mean the same thing.
However, until attributes are allowed to appertain to all the new
locations described by C++11, it would be useful to use their order to
"map" them onto the different nodes they should appertain. The
specific_attr_reverse_iterator provides some functionality towards that
goal.
Implementation
----------------------
The implementation is a slightly modified version of the code of the
corresponding forward iterator. A small difference is that the forward
iterator returns a pointer to the underlying type *T, whereas the
reverse one returns an object of type typedef
std::reverse_iterator<iterator
<http://llvm.org/docs/doxygen/html/classllvm_1_1SmallVectorTemplateCommon.html#a309d93eaafb8f5a8dfb7de2a231335ea>>.
For that reason, Decl::attr_rbegin() and Decl::attr_rend() for
attr_reverse_iterator check if the Decl has attributes, and if so,
return the begin or the end; otherwise, they return a sentinel RNull,
which is implemented as a static member of Decl.
Using the RNull sentinel is a bit awkward. Two alternatives are the
following:
1. Make the user responsible of checking if a Decl has an attributes
vector before trying to get a specific_attr_reverse_iterator. Trying to
get such an iterator on a Decl without any attrs will generate an
assertion failure. This approach gets rid of RNull, but requires users
to treat fwd and reverse iterators differently.
2. Each time the user tries to get a reverse iterator on a Decl without
attributes, create an empty attribute vector and return the beginning
(or the end) of it. This approach also removes the awkward RNull, but
may create many unneeded empty attribute vectors.
Please let me know if one of these alternatives is preferable.
Cheers!
Alex Tzannes
[[written during the Hacker Lab at last week's LLVM devellopers' meeting]]
diff --git a/include/clang/AST/Attr.h b/include/clang/AST/Attr.h
index 3ca0146..8f2ce66 100644
--- a/include/clang/AST/Attr.h
+++ b/include/clang/AST/Attr.h
@@ -228,6 +228,90 @@ inline specific_attr_iterator<SpecificAttr, Container>
return specific_attr_iterator<SpecificAttr, Container>(container.end());
}
+/// specific_attr_reverse_iterator - Iterates (in reverse order) over a
+/// subrange of an AttrVec, only providing attributes that are of a specifc
+/// type.
+template <typename SpecificAttr, typename Container = AttrVec>
+class specific_attr_reverse_iterator {
+ typedef typename Container::const_reverse_iterator RevIterator;
+
+ /// Current - The current, underlying iterator.
+ /// In order to ensure we don't dereference an invalid iterator unless
+ /// specifically requested, we don't necessarily advance this all the
+ /// way. Instead, we advance it when an operation is requested; if the
+ /// operation is acting on what should be a past-the-end iterator,
+ /// then we offer no guarantees, but this way we do not dererence a
+ /// past-the-end iterator when we move to a past-the-end position.
+ mutable RevIterator RevCurrent;
+
+ void BacktrackToPrevious() const {
+ while (!isa<SpecificAttr>(*RevCurrent))
+ ++RevCurrent;
+ }
+
+ void BacktrackToPrevious(RevIterator RI) const {
+ while (RevCurrent != RI && !isa<SpecificAttr>(*RevCurrent))
+ ++RevCurrent;
+ }
+
+public:
+ typedef SpecificAttr* value_type;
+ typedef SpecificAttr* reference;
+ typedef SpecificAttr* pointer;
+ typedef std::forward_iterator_tag iterator_category;
+ typedef std::ptrdiff_t difference_type;
+
+ specific_attr_reverse_iterator() : RevCurrent() { }
+ explicit specific_attr_reverse_iterator(RevIterator ri) : RevCurrent(ri) { }
+
+ reference operator*() const {
+ BacktrackToPrevious();
+ return cast<SpecificAttr>(*RevCurrent);
+ }
+ pointer operator->() const {
+ BacktrackToPrevious();
+ return cast<SpecificAttr>(*RevCurrent);
+ }
+
+ specific_attr_reverse_iterator& operator++() {
+ ++RevCurrent;
+ return *this;
+ }
+ specific_attr_reverse_iterator operator++(int) {
+ specific_attr_reverse_iterator Tmp(*this);
+ ++(*this);
+ return Tmp;
+ }
+
+ friend bool operator==(specific_attr_reverse_iterator Left,
+ specific_attr_reverse_iterator Right) {
+ if (Left.RevCurrent < Right.RevCurrent)
+ Left.BacktrackToPrevious(Right.RevCurrent);
+ else
+ Right.BacktrackToPrevious(Left.RevCurrent);
+ return Left.RevCurrent == Right.RevCurrent;
+ }
+ friend bool operator!=(specific_attr_reverse_iterator Left,
+ specific_attr_reverse_iterator Right) {
+ return !(Left == Right);
+ }
+
+};
+
+template <typename SpecificAttr, typename Container>
+inline specific_attr_reverse_iterator<SpecificAttr, Container>
+ specific_attr_rbegin(const Container& container) {
+ return specific_attr_reverse_iterator<SpecificAttr,
Container>(container.rbegin());
+}
+template <typename SpecificAttr, typename Container>
+inline specific_attr_reverse_iterator<SpecificAttr, Container>
+ specific_attr_rend(const Container& container) {
+ return specific_attr_reverse_iterator<SpecificAttr,
Container>(container.rend());
+}
+
template <typename SpecificAttr, typename Container>
inline bool hasSpecificAttr(const Container& container) {
return specific_attr_begin<SpecificAttr>(container) !=
diff --git a/include/clang/AST/DeclBase.h b/include/clang/AST/DeclBase.h
index 7edb1fe..75b4908 100644
--- a/include/clang/AST/DeclBase.h
+++ b/include/clang/AST/DeclBase.h
@@ -416,6 +416,10 @@ public:
}
typedef AttrVec::const_iterator attr_iterator;
+ typedef AttrVec::const_reverse_iterator attr_reverse_iterator;
+
+ /// \brief A null equivalent for reverse iterators
+ static attr_reverse_iterator RNull;
// FIXME: Do not rely on iterators having comparable singular values.
// Note that this should error out if they do not.
@@ -426,6 +430,14 @@ public:
return hasAttrs() ? getAttrs().end() : 0;
}
+
+ attr_reverse_iterator attr_rbegin() const {
+ return hasAttrs() ? getAttrs().rbegin() : RNull;
+ }
+ attr_reverse_iterator attr_rend() const {
+ return hasAttrs() ? getAttrs().rend() : RNull ;
+ }
+
template <typename T>
void dropAttr() {
if (!HasAttrs) return;
@@ -452,6 +464,17 @@ public:
return specific_attr_iterator<T>(attr_end());
}
+ template <typename T>
+ specific_attr_reverse_iterator<T> specific_attr_rbegin() const {
+ return specific_attr_reverse_iterator<T>(attr_rbegin());
+ }
+ template <typename T>
+ specific_attr_reverse_iterator<T> specific_attr_rend() const {
+ return specific_attr_reverse_iterator<T>(attr_rend());
+ }
template<typename T> T *getAttr() const {
return hasAttrs() ? getSpecificAttr<T>(getAttrs()) : 0;
}
diff --git a/lib/AST/DeclBase.cpp b/lib/AST/DeclBase.cpp
index 4400d50..3dd4fba 100644
--- a/lib/AST/DeclBase.cpp
+++ b/lib/AST/DeclBase.cpp
@@ -86,6 +86,8 @@ const char *DeclContext::getDeclKindName() const {
}
}
+Decl::attr_reverse_iterator Decl::RNull;
+
bool Decl::StatisticsEnabled = false;
void Decl::EnableStatistics() {
StatisticsEnabled = true;
_______________________________________________
cfe-dev mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-dev
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits