clang API Documentation

Lookup.h
Go to the documentation of this file.
00001 //===--- Lookup.h - Classes for name lookup ---------------------*- C++ -*-===//
00002 //
00003 //                     The LLVM Compiler Infrastructure
00004 //
00005 // This file is distributed under the University of Illinois Open Source
00006 // License. See LICENSE.TXT for details.
00007 //
00008 //===----------------------------------------------------------------------===//
00009 //
00010 // This file defines the LookupResult class, which is integral to
00011 // Sema's name-lookup subsystem.
00012 //
00013 //===----------------------------------------------------------------------===//
00014 
00015 #ifndef LLVM_CLANG_SEMA_LOOKUP_H
00016 #define LLVM_CLANG_SEMA_LOOKUP_H
00017 
00018 #include "clang/Sema/Sema.h"
00019 #include "clang/AST/DeclCXX.h"
00020 
00021 namespace clang {
00022 
00023 /// @brief Represents the results of name lookup.
00024 ///
00025 /// An instance of the LookupResult class captures the results of a
00026 /// single name lookup, which can return no result (nothing found),
00027 /// a single declaration, a set of overloaded functions, or an
00028 /// ambiguity. Use the getKind() method to determine which of these
00029 /// results occurred for a given lookup.
00030 class LookupResult {
00031 public:
00032   enum LookupResultKind {
00033     /// @brief No entity found met the criteria.
00034     NotFound = 0,
00035 
00036     /// @brief No entity found met the criteria within the current 
00037     /// instantiation,, but there were dependent base classes of the 
00038     /// current instantiation that could not be searched.
00039     NotFoundInCurrentInstantiation,
00040     
00041     /// @brief Name lookup found a single declaration that met the
00042     /// criteria.  getFoundDecl() will return this declaration.
00043     Found,
00044 
00045     /// @brief Name lookup found a set of overloaded functions that
00046     /// met the criteria.
00047     FoundOverloaded,
00048 
00049     /// @brief Name lookup found an unresolvable value declaration
00050     /// and cannot yet complete.  This only happens in C++ dependent
00051     /// contexts with dependent using declarations.
00052     FoundUnresolvedValue,
00053 
00054     /// @brief Name lookup results in an ambiguity; use
00055     /// getAmbiguityKind to figure out what kind of ambiguity
00056     /// we have.
00057     Ambiguous
00058   };
00059 
00060   enum AmbiguityKind {
00061     /// Name lookup results in an ambiguity because multiple
00062     /// entities that meet the lookup criteria were found in
00063     /// subobjects of different types. For example:
00064     /// @code
00065     /// struct A { void f(int); }
00066     /// struct B { void f(double); }
00067     /// struct C : A, B { };
00068     /// void test(C c) {
00069     ///   c.f(0); // error: A::f and B::f come from subobjects of different
00070     ///           // types. overload resolution is not performed.
00071     /// }
00072     /// @endcode
00073     AmbiguousBaseSubobjectTypes,
00074 
00075     /// Name lookup results in an ambiguity because multiple
00076     /// nonstatic entities that meet the lookup criteria were found
00077     /// in different subobjects of the same type. For example:
00078     /// @code
00079     /// struct A { int x; };
00080     /// struct B : A { };
00081     /// struct C : A { };
00082     /// struct D : B, C { };
00083     /// int test(D d) {
00084     ///   return d.x; // error: 'x' is found in two A subobjects (of B and C)
00085     /// }
00086     /// @endcode
00087     AmbiguousBaseSubobjects,
00088 
00089     /// Name lookup results in an ambiguity because multiple definitions
00090     /// of entity that meet the lookup criteria were found in different
00091     /// declaration contexts.
00092     /// @code
00093     /// namespace A {
00094     ///   int i;
00095     ///   namespace B { int i; }
00096     ///   int test() {
00097     ///     using namespace B;
00098     ///     return i; // error 'i' is found in namespace A and A::B
00099     ///    }
00100     /// }
00101     /// @endcode
00102     AmbiguousReference,
00103 
00104     /// Name lookup results in an ambiguity because an entity with a
00105     /// tag name was hidden by an entity with an ordinary name from
00106     /// a different context.
00107     /// @code
00108     /// namespace A { struct Foo {}; }
00109     /// namespace B { void Foo(); }
00110     /// namespace C {
00111     ///   using namespace A;
00112     ///   using namespace B;
00113     /// }
00114     /// void test() {
00115     ///   C::Foo(); // error: tag 'A::Foo' is hidden by an object in a
00116     ///             // different namespace
00117     /// }
00118     /// @endcode
00119     AmbiguousTagHiding
00120   };
00121 
00122   /// A little identifier for flagging temporary lookup results.
00123   enum TemporaryToken {
00124     Temporary
00125   };
00126 
00127   typedef UnresolvedSetImpl::iterator iterator;
00128 
00129   LookupResult(Sema &SemaRef, const DeclarationNameInfo &NameInfo,
00130                Sema::LookupNameKind LookupKind,
00131                Sema::RedeclarationKind Redecl = Sema::NotForRedeclaration)
00132     : ResultKind(NotFound),
00133       Paths(0),
00134       NamingClass(0),
00135       SemaRef(SemaRef),
00136       NameInfo(NameInfo),
00137       LookupKind(LookupKind),
00138       IDNS(0),
00139       Redecl(Redecl != Sema::NotForRedeclaration),
00140       HideTags(true),
00141       Diagnose(Redecl == Sema::NotForRedeclaration)
00142   {
00143     configure();
00144   }
00145 
00146   // TODO: consider whether this constructor should be restricted to take
00147   // as input a const IndentifierInfo* (instead of Name),
00148   // forcing other cases towards the constructor taking a DNInfo.
00149   LookupResult(Sema &SemaRef, DeclarationName Name,
00150                SourceLocation NameLoc, Sema::LookupNameKind LookupKind,
00151                Sema::RedeclarationKind Redecl = Sema::NotForRedeclaration)
00152     : ResultKind(NotFound),
00153       Paths(0),
00154       NamingClass(0),
00155       SemaRef(SemaRef),
00156       NameInfo(Name, NameLoc),
00157       LookupKind(LookupKind),
00158       IDNS(0),
00159       Redecl(Redecl != Sema::NotForRedeclaration),
00160       HideTags(true),
00161       Diagnose(Redecl == Sema::NotForRedeclaration)
00162   {
00163     configure();
00164   }
00165 
00166   /// Creates a temporary lookup result, initializing its core data
00167   /// using the information from another result.  Diagnostics are always
00168   /// disabled.
00169   LookupResult(TemporaryToken _, const LookupResult &Other)
00170     : ResultKind(NotFound),
00171       Paths(0),
00172       NamingClass(0),
00173       SemaRef(Other.SemaRef),
00174       NameInfo(Other.NameInfo),
00175       LookupKind(Other.LookupKind),
00176       IDNS(Other.IDNS),
00177       Redecl(Other.Redecl),
00178       HideTags(Other.HideTags),
00179       Diagnose(false)
00180   {}
00181 
00182   ~LookupResult() {
00183     if (Diagnose) diagnose();
00184     if (Paths) deletePaths(Paths);
00185   }
00186 
00187   /// Gets the name info to look up.
00188   const DeclarationNameInfo &getLookupNameInfo() const {
00189     return NameInfo;
00190   }
00191 
00192   /// \brief Sets the name info to look up.
00193   void setLookupNameInfo(const DeclarationNameInfo &NameInfo) {
00194     this->NameInfo = NameInfo;
00195   }
00196 
00197   /// Gets the name to look up.
00198   DeclarationName getLookupName() const {
00199     return NameInfo.getName();
00200   }
00201 
00202   /// \brief Sets the name to look up.
00203   void setLookupName(DeclarationName Name) {
00204     NameInfo.setName(Name);
00205   }
00206 
00207   /// Gets the kind of lookup to perform.
00208   Sema::LookupNameKind getLookupKind() const {
00209     return LookupKind;
00210   }
00211 
00212   /// True if this lookup is just looking for an existing declaration.
00213   bool isForRedeclaration() const {
00214     return Redecl;
00215   }
00216 
00217   /// \brief Determine whether this lookup is permitted to see hidden
00218   /// declarations, such as those in modules that have not yet been imported.
00219   bool isHiddenDeclarationVisible() const {
00220     return Redecl || LookupKind == Sema::LookupTagName;
00221   }
00222   
00223   /// Sets whether tag declarations should be hidden by non-tag
00224   /// declarations during resolution.  The default is true.
00225   void setHideTags(bool Hide) {
00226     HideTags = Hide;
00227   }
00228 
00229   bool isAmbiguous() const {
00230     return getResultKind() == Ambiguous;
00231   }
00232 
00233   /// Determines if this names a single result which is not an
00234   /// unresolved value using decl.  If so, it is safe to call
00235   /// getFoundDecl().
00236   bool isSingleResult() const {
00237     return getResultKind() == Found;
00238   }
00239 
00240   /// Determines if the results are overloaded.
00241   bool isOverloadedResult() const {
00242     return getResultKind() == FoundOverloaded;
00243   }
00244 
00245   bool isUnresolvableResult() const {
00246     return getResultKind() == FoundUnresolvedValue;
00247   }
00248 
00249   LookupResultKind getResultKind() const {
00250     sanity();
00251     return ResultKind;
00252   }
00253 
00254   AmbiguityKind getAmbiguityKind() const {
00255     assert(isAmbiguous());
00256     return Ambiguity;
00257   }
00258 
00259   const UnresolvedSetImpl &asUnresolvedSet() const {
00260     return Decls;
00261   }
00262 
00263   iterator begin() const { return iterator(Decls.begin()); }
00264   iterator end() const { return iterator(Decls.end()); }
00265 
00266   /// \brief Return true if no decls were found
00267   bool empty() const { return Decls.empty(); }
00268 
00269   /// \brief Return the base paths structure that's associated with
00270   /// these results, or null if none is.
00271   CXXBasePaths *getBasePaths() const {
00272     return Paths;
00273   }
00274 
00275   /// \brief Determine whether the given declaration is visible to the
00276   /// program.
00277   static bool isVisible(NamedDecl *D) {
00278     // If this declaration is not hidden, it's visible.
00279     if (!D->isHidden())
00280       return true;
00281     
00282     // FIXME: We should be allowed to refer to a module-private name from 
00283     // within the same module, e.g., during template instantiation.
00284     // This requires us know which module a particular declaration came from.
00285     return false;
00286   }
00287   
00288   /// \brief Retrieve the accepted (re)declaration of the given declaration,
00289   /// if there is one.
00290   NamedDecl *getAcceptableDecl(NamedDecl *D) const {
00291     if (!D->isInIdentifierNamespace(IDNS))
00292       return 0;
00293     
00294     if (isHiddenDeclarationVisible() || isVisible(D))
00295       return D;
00296     
00297     return getAcceptableDeclSlow(D);
00298   }
00299   
00300 private:
00301   NamedDecl *getAcceptableDeclSlow(NamedDecl *D) const;
00302 public:
00303   
00304   /// \brief Returns the identifier namespace mask for this lookup.
00305   unsigned getIdentifierNamespace() const {
00306     return IDNS;
00307   }
00308 
00309   /// \brief Returns whether these results arose from performing a
00310   /// lookup into a class.
00311   bool isClassLookup() const {
00312     return NamingClass != 0;
00313   }
00314 
00315   /// \brief Returns the 'naming class' for this lookup, i.e. the
00316   /// class which was looked into to find these results.
00317   ///
00318   /// C++0x [class.access.base]p5:
00319   ///   The access to a member is affected by the class in which the
00320   ///   member is named. This naming class is the class in which the
00321   ///   member name was looked up and found. [Note: this class can be
00322   ///   explicit, e.g., when a qualified-id is used, or implicit,
00323   ///   e.g., when a class member access operator (5.2.5) is used
00324   ///   (including cases where an implicit "this->" is added). If both
00325   ///   a class member access operator and a qualified-id are used to
00326   ///   name the member (as in p->T::m), the class naming the member
00327   ///   is the class named by the nested-name-specifier of the
00328   ///   qualified-id (that is, T). -- end note ]
00329   ///
00330   /// This is set by the lookup routines when they find results in a class.
00331   CXXRecordDecl *getNamingClass() const {
00332     return NamingClass;
00333   }
00334 
00335   /// \brief Sets the 'naming class' for this lookup.
00336   void setNamingClass(CXXRecordDecl *Record) {
00337     NamingClass = Record;
00338   }
00339 
00340   /// \brief Returns the base object type associated with this lookup;
00341   /// important for [class.protected].  Most lookups do not have an
00342   /// associated base object.
00343   QualType getBaseObjectType() const {
00344     return BaseObjectType;
00345   }
00346 
00347   /// \brief Sets the base object type for this lookup.
00348   void setBaseObjectType(QualType T) {
00349     BaseObjectType = T;
00350   }
00351 
00352   /// \brief Add a declaration to these results with its natural access.
00353   /// Does not test the acceptance criteria.
00354   void addDecl(NamedDecl *D) {
00355     addDecl(D, D->getAccess());
00356   }
00357 
00358   /// \brief Add a declaration to these results with the given access.
00359   /// Does not test the acceptance criteria.
00360   void addDecl(NamedDecl *D, AccessSpecifier AS) {
00361     Decls.addDecl(D, AS);
00362     ResultKind = Found;
00363   }
00364 
00365   /// \brief Add all the declarations from another set of lookup
00366   /// results.
00367   void addAllDecls(const LookupResult &Other) {
00368     Decls.append(Other.Decls.begin(), Other.Decls.end());
00369     ResultKind = Found;
00370   }
00371 
00372   /// \brief Determine whether no result was found because we could not
00373   /// search into dependent base classes of the current instantiation.
00374   bool wasNotFoundInCurrentInstantiation() const {
00375     return ResultKind == NotFoundInCurrentInstantiation;
00376   }
00377   
00378   /// \brief Note that while no result was found in the current instantiation,
00379   /// there were dependent base classes that could not be searched.
00380   void setNotFoundInCurrentInstantiation() {
00381     assert(ResultKind == NotFound && Decls.empty());
00382     ResultKind = NotFoundInCurrentInstantiation;
00383   }
00384   
00385   /// \brief Resolves the result kind of the lookup, possibly hiding
00386   /// decls.
00387   ///
00388   /// This should be called in any environment where lookup might
00389   /// generate multiple lookup results.
00390   void resolveKind();
00391 
00392   /// \brief Re-resolves the result kind of the lookup after a set of
00393   /// removals has been performed.
00394   void resolveKindAfterFilter() {
00395     if (Decls.empty()) {
00396       if (ResultKind != NotFoundInCurrentInstantiation)
00397         ResultKind = NotFound;
00398 
00399       if (Paths) {
00400         deletePaths(Paths);
00401         Paths = 0;
00402       }
00403     } else {
00404       AmbiguityKind SavedAK = Ambiguity;
00405       ResultKind = Found;
00406       resolveKind();
00407 
00408       // If we didn't make the lookup unambiguous, restore the old
00409       // ambiguity kind.
00410       if (ResultKind == Ambiguous) {
00411         Ambiguity = SavedAK;
00412       } else if (Paths) {
00413         deletePaths(Paths);
00414         Paths = 0;
00415       }
00416     }
00417   }
00418 
00419   template <class DeclClass>
00420   DeclClass *getAsSingle() const {
00421     if (getResultKind() != Found) return 0;
00422     return dyn_cast<DeclClass>(getFoundDecl());
00423   }
00424 
00425   /// \brief Fetch the unique decl found by this lookup.  Asserts
00426   /// that one was found.
00427   ///
00428   /// This is intended for users who have examined the result kind
00429   /// and are certain that there is only one result.
00430   NamedDecl *getFoundDecl() const {
00431     assert(getResultKind() == Found
00432            && "getFoundDecl called on non-unique result");
00433     return (*begin())->getUnderlyingDecl();
00434   }
00435 
00436   /// Fetches a representative decl.  Useful for lazy diagnostics.
00437   NamedDecl *getRepresentativeDecl() const {
00438     assert(!Decls.empty() && "cannot get representative of empty set");
00439     return *begin();
00440   }
00441 
00442   /// \brief Asks if the result is a single tag decl.
00443   bool isSingleTagDecl() const {
00444     return getResultKind() == Found && isa<TagDecl>(getFoundDecl());
00445   }
00446 
00447   /// \brief Make these results show that the name was found in
00448   /// base classes of different types.
00449   ///
00450   /// The given paths object is copied and invalidated.
00451   void setAmbiguousBaseSubobjectTypes(CXXBasePaths &P);
00452 
00453   /// \brief Make these results show that the name was found in
00454   /// distinct base classes of the same type.
00455   ///
00456   /// The given paths object is copied and invalidated.
00457   void setAmbiguousBaseSubobjects(CXXBasePaths &P);
00458 
00459   /// \brief Make these results show that the name was found in
00460   /// different contexts and a tag decl was hidden by an ordinary
00461   /// decl in a different context.
00462   void setAmbiguousQualifiedTagHiding() {
00463     setAmbiguous(AmbiguousTagHiding);
00464   }
00465 
00466   /// \brief Clears out any current state.
00467   void clear() {
00468     ResultKind = NotFound;
00469     Decls.clear();
00470     if (Paths) deletePaths(Paths);
00471     Paths = NULL;
00472     NamingClass = 0;
00473   }
00474 
00475   /// \brief Clears out any current state and re-initializes for a
00476   /// different kind of lookup.
00477   void clear(Sema::LookupNameKind Kind) {
00478     clear();
00479     LookupKind = Kind;
00480     configure();
00481   }
00482 
00483   /// \brief Change this lookup's redeclaration kind.
00484   void setRedeclarationKind(Sema::RedeclarationKind RK) {
00485     Redecl = RK;
00486     configure();
00487   }
00488 
00489   void print(raw_ostream &);
00490 
00491   /// Suppress the diagnostics that would normally fire because of this
00492   /// lookup.  This happens during (e.g.) redeclaration lookups.
00493   void suppressDiagnostics() {
00494     Diagnose = false;
00495   }
00496 
00497   /// Determines whether this lookup is suppressing diagnostics.
00498   bool isSuppressingDiagnostics() const {
00499     return !Diagnose;
00500   }
00501 
00502   /// Sets a 'context' source range.
00503   void setContextRange(SourceRange SR) {
00504     NameContextRange = SR;
00505   }
00506 
00507   /// Gets the source range of the context of this name; for C++
00508   /// qualified lookups, this is the source range of the scope
00509   /// specifier.
00510   SourceRange getContextRange() const {
00511     return NameContextRange;
00512   }
00513 
00514   /// Gets the location of the identifier.  This isn't always defined:
00515   /// sometimes we're doing lookups on synthesized names.
00516   SourceLocation getNameLoc() const {
00517     return NameInfo.getLoc();
00518   }
00519 
00520   /// \brief Get the Sema object that this lookup result is searching
00521   /// with.
00522   Sema &getSema() const { return SemaRef; }
00523 
00524   /// A class for iterating through a result set and possibly
00525   /// filtering out results.  The results returned are possibly
00526   /// sugared.
00527   class Filter {
00528     LookupResult &Results;
00529     LookupResult::iterator I;
00530     bool Changed;
00531     bool CalledDone;
00532     
00533     friend class LookupResult;
00534     Filter(LookupResult &Results)
00535       : Results(Results), I(Results.begin()), Changed(false), CalledDone(false)
00536     {}
00537 
00538   public:
00539     ~Filter() {
00540       assert(CalledDone &&
00541              "LookupResult::Filter destroyed without done() call");
00542     }
00543 
00544     bool hasNext() const {
00545       return I != Results.end();
00546     }
00547 
00548     NamedDecl *next() {
00549       assert(I != Results.end() && "next() called on empty filter");
00550       return *I++;
00551     }
00552 
00553     /// Restart the iteration.
00554     void restart() {
00555       I = Results.begin();
00556     }
00557 
00558     /// Erase the last element returned from this iterator.
00559     void erase() {
00560       Results.Decls.erase(--I);
00561       Changed = true;
00562     }
00563 
00564     /// Replaces the current entry with the given one, preserving the
00565     /// access bits.
00566     void replace(NamedDecl *D) {
00567       Results.Decls.replace(I-1, D);
00568       Changed = true;
00569     }
00570 
00571     /// Replaces the current entry with the given one.
00572     void replace(NamedDecl *D, AccessSpecifier AS) {
00573       Results.Decls.replace(I-1, D, AS);
00574       Changed = true;
00575     }
00576 
00577     void done() {
00578       assert(!CalledDone && "done() called twice");
00579       CalledDone = true;
00580 
00581       if (Changed)
00582         Results.resolveKindAfterFilter();
00583     }
00584   };
00585 
00586   /// Create a filter for this result set.
00587   Filter makeFilter() {
00588     return Filter(*this);
00589   }
00590 
00591 private:
00592   void diagnose() {
00593     if (isAmbiguous())
00594       SemaRef.DiagnoseAmbiguousLookup(*this);
00595     else if (isClassLookup() && SemaRef.getLangOpts().AccessControl)
00596       SemaRef.CheckLookupAccess(*this);
00597   }
00598 
00599   void setAmbiguous(AmbiguityKind AK) {
00600     ResultKind = Ambiguous;
00601     Ambiguity = AK;
00602   }
00603 
00604   void addDeclsFromBasePaths(const CXXBasePaths &P);
00605   void configure();
00606 
00607   // Sanity checks.
00608   void sanityImpl() const;
00609 
00610   void sanity() const {
00611 #ifndef NDEBUG
00612     sanityImpl();
00613 #endif
00614   }
00615 
00616   bool sanityCheckUnresolved() const {
00617     for (iterator I = begin(), E = end(); I != E; ++I)
00618       if (isa<UnresolvedUsingValueDecl>(*I))
00619         return true;
00620     return false;
00621   }
00622 
00623   static void deletePaths(CXXBasePaths *);
00624 
00625   // Results.
00626   LookupResultKind ResultKind;
00627   AmbiguityKind Ambiguity; // ill-defined unless ambiguous
00628   UnresolvedSet<8> Decls;
00629   CXXBasePaths *Paths;
00630   CXXRecordDecl *NamingClass;
00631   QualType BaseObjectType;
00632 
00633   // Parameters.
00634   Sema &SemaRef;
00635   DeclarationNameInfo NameInfo;
00636   SourceRange NameContextRange;
00637   Sema::LookupNameKind LookupKind;
00638   unsigned IDNS; // set by configure()
00639 
00640   bool Redecl;
00641 
00642   /// \brief True if tag declarations should be hidden if non-tags
00643   ///   are present
00644   bool HideTags;
00645 
00646   bool Diagnose;
00647 };
00648 
00649   /// \brief Consumes visible declarations found when searching for
00650   /// all visible names within a given scope or context.
00651   ///
00652   /// This abstract class is meant to be subclassed by clients of \c
00653   /// Sema::LookupVisibleDecls(), each of which should override the \c
00654   /// FoundDecl() function to process declarations as they are found.
00655   class VisibleDeclConsumer {
00656   public:
00657     /// \brief Destroys the visible declaration consumer.
00658     virtual ~VisibleDeclConsumer();
00659 
00660     /// \brief Invoked each time \p Sema::LookupVisibleDecls() finds a
00661     /// declaration visible from the current scope or context.
00662     ///
00663     /// \param ND the declaration found.
00664     ///
00665     /// \param Hiding a declaration that hides the declaration \p ND,
00666     /// or NULL if no such declaration exists.
00667     ///
00668     /// \param Ctx the original context from which the lookup started.
00669     ///
00670     /// \param InBaseClass whether this declaration was found in base
00671     /// class of the context we searched.
00672     virtual void FoundDecl(NamedDecl *ND, NamedDecl *Hiding, DeclContext *Ctx,
00673                            bool InBaseClass) = 0;
00674   };
00675 
00676 /// \brief A class for storing results from argument-dependent lookup.
00677 class ADLResult {
00678 private:
00679   /// A map from canonical decls to the 'most recent' decl.
00680   llvm::DenseMap<NamedDecl*, NamedDecl*> Decls;
00681 
00682 public:
00683   /// Adds a new ADL candidate to this map.
00684   void insert(NamedDecl *D);
00685 
00686   /// Removes any data associated with a given decl.
00687   void erase(NamedDecl *D) {
00688     Decls.erase(cast<NamedDecl>(D->getCanonicalDecl()));
00689   }
00690 
00691   class iterator {
00692     typedef llvm::DenseMap<NamedDecl*,NamedDecl*>::iterator inner_iterator;
00693     inner_iterator iter;
00694 
00695     friend class ADLResult;
00696     iterator(const inner_iterator &iter) : iter(iter) {}
00697   public:
00698     iterator() {}
00699 
00700     iterator &operator++() { ++iter; return *this; }
00701     iterator operator++(int) { return iterator(iter++); }
00702 
00703     NamedDecl *operator*() const { return iter->second; }
00704 
00705     bool operator==(const iterator &other) const { return iter == other.iter; }
00706     bool operator!=(const iterator &other) const { return iter != other.iter; }
00707   };
00708 
00709   iterator begin() { return iterator(Decls.begin()); }
00710   iterator end() { return iterator(Decls.end()); }
00711 };
00712 
00713 }
00714 
00715 #endif