From 44b4321feab46299d3f5cfd404680884752a0fcf Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Thu, 11 Dec 2008 16:49:14 +0000 Subject: [PATCH] Unifies the name-lookup mechanisms used in various parts of the AST and separates lexical name lookup from qualified name lookup. In particular: * Make DeclContext the central data structure for storing and looking up declarations within existing declarations, e.g., members of structs/unions/classes, enumerators in C++0x enums, members of C++ namespaces, and (later) members of Objective-C interfaces/implementations. DeclContext uses a lazily-constructed data structure optimized for fast lookup (array for small contexts, hash table for larger contexts). * Implement C++ qualified name lookup in terms of lookup into DeclContext. * Implement C++ unqualified name lookup in terms of qualified+unqualified name lookup (since unqualified lookup is not purely lexical in C++!) * Limit the use of the chains of declarations stored in IdentifierInfo to those names declared lexically. * Eliminate CXXFieldDecl, collapsing its behavior into FieldDecl. (FieldDecl is now a ScopedDecl). * Make RecordDecl into a DeclContext and eliminates its Members/NumMembers fields (since one can just iterate through the DeclContext to get the fields). git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@60878 91177308-0d34-0410-b5e6-96231b3b80d8 --- Driver/PrintParserCallbacks.cpp | 5 +- Driver/RewriteObjC.cpp | 41 ++-- include/clang/AST/ASTContext.h | 8 +- include/clang/AST/Decl.h | 195 +++++++++++------- include/clang/AST/DeclBase.h | 193 ++++++++++++++--- include/clang/AST/DeclCXX.h | 58 +----- include/clang/AST/DeclObjC.h | 10 +- include/clang/AST/DeclarationName.h | 4 + include/clang/Parse/Action.h | 4 +- include/clang/Parse/Scope.h | 14 ++ lib/AST/ASTContext.cpp | 74 ++++--- lib/AST/Decl.cpp | 59 +++--- lib/AST/DeclBase.cpp | 276 ++++++++++++++++++++++++- lib/AST/DeclCXX.cpp | 16 +- lib/AST/DeclObjC.cpp | 4 +- lib/AST/DeclSerialization.cpp | 63 +++--- lib/AST/DeclarationName.cpp | 6 + lib/AST/Expr.cpp | 15 +- lib/AST/ExprConstant.cpp | 8 +- lib/Analysis/RegionStore.cpp | 9 +- lib/CodeGen/CGDebugInfo.cpp | 9 +- lib/CodeGen/CGExprAgg.cpp | 16 +- lib/CodeGen/CGExprConstant.cpp | 19 +- lib/CodeGen/CGObjCMac.cpp | 15 +- lib/CodeGen/CodeGenModule.cpp | 36 ++-- lib/CodeGen/CodeGenTypes.cpp | 39 ++-- lib/Parse/ParseDecl.cpp | 6 +- lib/Sema/CXXFieldCollector.h | 10 +- lib/Sema/IdentifierResolver.cpp | 7 +- lib/Sema/IdentifierResolver.h | 3 +- lib/Sema/Sema.cpp | 2 +- lib/Sema/Sema.h | 11 +- lib/Sema/SemaCXXScopeSpec.cpp | 25 ++- lib/Sema/SemaDecl.cpp | 297 +++++++++++++++++++-------- lib/Sema/SemaDeclAttr.cpp | 6 +- lib/Sema/SemaDeclCXX.cpp | 73 +++---- lib/Sema/SemaDeclObjC.cpp | 2 +- lib/Sema/SemaExpr.cpp | 32 ++- lib/Sema/SemaExprCXX.cpp | 7 +- lib/Sema/SemaInit.cpp | 28 ++- lib/Sema/SemaOverload.cpp | 23 +-- test/SemaCXX/namespace.cpp | 3 +- test/SemaCXX/qualified-id-lookup.cpp | 53 +++++ 43 files changed, 1235 insertions(+), 549 deletions(-) create mode 100644 test/SemaCXX/qualified-id-lookup.cpp diff --git a/Driver/PrintParserCallbacks.cpp b/Driver/PrintParserCallbacks.cpp index f3ddb23a5f..8ec45f2703 100644 --- a/Driver/PrintParserCallbacks.cpp +++ b/Driver/PrintParserCallbacks.cpp @@ -185,13 +185,14 @@ namespace { /// Act on @defs() element found when parsing a structure. ClassName is the /// name of the referenced class. - virtual void ActOnDefs(Scope *S, SourceLocation DeclStart, + virtual void ActOnDefs(Scope *S, DeclTy *TagD, SourceLocation DeclStart, IdentifierInfo *ClassName, llvm::SmallVectorImpl &Decls) { llvm::cout << __FUNCTION__ << "\n"; } - virtual DeclTy *ActOnField(Scope *S, SourceLocation DeclStart, + virtual DeclTy *ActOnField(Scope *S, DeclTy *TagD, + SourceLocation DeclStart, Declarator &D, ExprTy *BitfieldWidth) { llvm::cout << __FUNCTION__ << "\n"; return 0; diff --git a/Driver/RewriteObjC.cpp b/Driver/RewriteObjC.cpp index 1b7ce5bece..290a668563 100644 --- a/Driver/RewriteObjC.cpp +++ b/Driver/RewriteObjC.cpp @@ -2169,14 +2169,18 @@ QualType RewriteObjC::getSuperStructType() { FieldTypes[0] = Context->getObjCIdType(); // struct objc_class *super; FieldTypes[1] = Context->getObjCClassType(); + // Create fields - FieldDecl *FieldDecls[2]; - - for (unsigned i = 0; i < 2; ++i) - FieldDecls[i] = FieldDecl::Create(*Context, SourceLocation(), 0, - FieldTypes[i]); + for (unsigned i = 0; i < 2; ++i) { + SuperStructDecl->addDecl(*Context, + FieldDecl::Create(*Context, SuperStructDecl, + SourceLocation(), 0, + FieldTypes[i], /*BitWidth=*/0, + /*Mutable=*/false, 0), + true); + } - SuperStructDecl->defineBody(*Context, FieldDecls, 4); + SuperStructDecl->completeDefinition(*Context); } return Context->getTagDeclType(SuperStructDecl); } @@ -2196,14 +2200,20 @@ QualType RewriteObjC::getConstantStringStructType() { FieldTypes[2] = Context->getPointerType(Context->CharTy); // long length; FieldTypes[3] = Context->LongTy; + // Create fields - FieldDecl *FieldDecls[4]; - - for (unsigned i = 0; i < 4; ++i) - FieldDecls[i] = FieldDecl::Create(*Context, SourceLocation(), 0, - FieldTypes[i]); - - ConstantStringDecl->defineBody(*Context, FieldDecls, 4); + for (unsigned i = 0; i < 4; ++i) { + ConstantStringDecl->addDecl(*Context, + FieldDecl::Create(*Context, + ConstantStringDecl, + SourceLocation(), 0, + FieldTypes[i], + /*BitWidth=*/0, + /*Mutable=*/true, 0), + true); + } + + ConstantStringDecl->completeDefinition(*Context); } return Context->getTagDeclType(ConstantStringDecl); } @@ -3788,8 +3798,9 @@ Stmt *RewriteObjC::SynthesizeBlockCall(CallExpr *Exp) { ParenExpr *PE = new ParenExpr(SourceLocation(), SourceLocation(), BlkCast); //PE->dump(); - FieldDecl *FD = FieldDecl::Create(*Context, SourceLocation(), - &Context->Idents.get("FuncPtr"), Context->VoidPtrTy); + FieldDecl *FD = FieldDecl::Create(*Context, 0, SourceLocation(), + &Context->Idents.get("FuncPtr"), Context->VoidPtrTy, + /*BitWidth=*/0, /*Mutable=*/true, 0); MemberExpr *ME = new MemberExpr(PE, true, FD, SourceLocation(), FD->getType()); CastExpr *FunkCast = new CStyleCastExpr(PtrToFuncCastType, ME, PtrToFuncCastType, SourceLocation(), SourceLocation()); diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h index 2a8b1c8a5b..45bb2c3637 100644 --- a/include/clang/AST/ASTContext.h +++ b/include/clang/AST/ASTContext.h @@ -513,10 +513,12 @@ private: void InitBuiltinTypes(); void InitBuiltinType(QualType &R, BuiltinType::Kind K); - /// setRecordDefinition - Used by RecordDecl::defineBody to inform ASTContext - /// about which RecordDecl serves as the definition of a particular - /// struct/union/class. This will eventually be used by enums as well. + /// setTagDefinition - Used by RecordDecl::completeDefinition and + /// EnumDecl::completeDefinition to inform + /// about which RecordDecl/EnumDecl serves as the definition of a particular + /// struct/union/class/enum. void setTagDefinition(TagDecl* R); + friend class EnumDecl; friend class RecordDecl; // Return the ObjC type encoding for a given type. diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h index 8fbb3f00e9..3b0eb551bb 100644 --- a/include/clang/AST/Decl.h +++ b/include/clang/AST/Decl.h @@ -115,12 +115,6 @@ class ScopedDecl : public NamedDecl { /// such as "int X, Y, *Z;" this indicates Decl for the next declarator. ScopedDecl *NextDeclarator; - /// When this decl is in scope while parsing, the Next field contains a - /// pointer to the shadowed decl of the same name. When the scope is popped, - /// Decls are relinked onto a containing decl object. - /// - ScopedDecl *Next; - /// DeclCtx - Holds either a DeclContext* or a MultipleDC*. /// For declarations that don't contain C++ scope specifiers, it contains /// the DeclContext where the ScopedDecl was declared. @@ -150,7 +144,7 @@ class ScopedDecl : public NamedDecl { protected: ScopedDecl(Kind DK, DeclContext *DC, SourceLocation L, DeclarationName N, ScopedDecl *PrevDecl) - : NamedDecl(DK, L, N), NextDeclarator(PrevDecl), Next(0), + : NamedDecl(DK, L, N), NextDeclarator(PrevDecl), DeclCtx(reinterpret_cast(DC)) {} virtual ~ScopedDecl(); @@ -188,9 +182,6 @@ public: void setLexicalDeclContext(DeclContext *DC); - ScopedDecl *getNext() const { return Next; } - void setNext(ScopedDecl *N) { Next = N; } - /// getNextDeclarator - If this decl was part of a multi-declarator /// declaration, such as "int X, Y, *Z;" this returns the decl for the next /// declarator. Otherwise it returns null. @@ -680,22 +671,31 @@ protected: /// FieldDecl - An instance of this class is created by Sema::ActOnField to /// represent a member of a struct/union/class. -class FieldDecl : public NamedDecl { +class FieldDecl : public ScopedDecl { + bool Mutable : 1; QualType DeclType; Expr *BitWidth; protected: - FieldDecl(Kind DK, SourceLocation L, IdentifierInfo *Id, QualType T, - Expr *BW = NULL) - : NamedDecl(DK, L, Id), DeclType(T), BitWidth(BW) {} - FieldDecl(SourceLocation L, IdentifierInfo *Id, QualType T, Expr *BW) - : NamedDecl(Field, L, Id), DeclType(T), BitWidth(BW) {} + FieldDecl(Kind DK, DeclContext *DC, SourceLocation L, + IdentifierInfo *Id, QualType T, Expr *BW, bool Mutable, + ScopedDecl *PrevDecl) + : ScopedDecl(DK, DC, L, Id, PrevDecl), Mutable(Mutable), DeclType(T), + BitWidth(BW) + { } + public: - static FieldDecl *Create(ASTContext &C, SourceLocation L, IdentifierInfo *Id, - QualType T, Expr *BW = NULL); + static FieldDecl *Create(ASTContext &C, DeclContext *DC, SourceLocation L, + IdentifierInfo *Id, QualType T, Expr *BW, + bool Mutable, ScopedDecl *PrevDecl); QualType getType() const { return DeclType; } - + + /// isMutable - Determines whether this field is mutable (C++ only). + bool isMutable() const { return Mutable; } + + /// isBitfield - Determines whether this field is a bitfield. bool isBitField() const { return BitWidth != NULL; } + Expr *getBitWidth() const { return BitWidth; } // Implement isa/cast/dyncast/etc. static bool classof(const Decl *D) { @@ -888,9 +888,6 @@ protected: /// EnumDecl - Represents an enum. As an extension, we allow forward-declared /// enums. class EnumDecl : public TagDecl, public DeclContext { - // EnumDecl's DeclChain points to a linked list of EnumConstantDecl's which - // are linked together through their getNextDeclarator pointers. - /// IntegerType - This represent the integer type that the enum corresponds /// to for code generation purposes. Note that the enumerator constants may /// have a different type than this does. @@ -908,30 +905,46 @@ public: virtual void Destroy(ASTContext& C); - /// defineElements - When created, EnumDecl correspond to a forward declared - /// enum. This method is used to mark the decl as being defined, with the - /// specified list of enums. - void defineElements(EnumConstantDecl *ListHead, QualType NewType) { - assert(!isDefinition() && "Cannot redefine enums!"); - setDeclChain(ListHead); - setDefinition(true); - - IntegerType = NewType; - } + /// completeDefinition - When created, the EnumDecl corresponds to a + /// forward-declared enum. This method is used to mark the + /// declaration as being defined; it's enumerators have already been + /// added (via DeclContext::addDecl). NewType is the new underlying + /// type of the enumeration type. + void completeDefinition(ASTContext &C, QualType NewType); + // enumerator_iterator - Iterates through the enumerators of this + // enumeration. + struct enumerator_iterator : public DeclContext::decl_iterator { + typedef EnumConstantDecl* value_type; + typedef EnumConstantDecl* reference; + typedef EnumConstantDecl* pointer; + + enumerator_iterator() : DeclContext::decl_iterator() { } + + explicit enumerator_iterator(DeclContext::decl_iterator Pos) + : DeclContext::decl_iterator(Pos) { } + + reference operator*() const { + return cast(DeclContext::decl_iterator::operator*()); + } + + pointer operator->() const { + return cast(DeclContext::decl_iterator::operator*()); + } + }; + + enumerator_iterator enumerator_begin() const { + return enumerator_iterator(this->decls_begin()); + } + + enumerator_iterator enumerator_end() const { + return enumerator_iterator(this->decls_end()); + } + /// getIntegerType - Return the integer type this enum decl corresponds to. /// This returns a null qualtype for an enum forward definition. QualType getIntegerType() const { return IntegerType; } - - /// getEnumConstantList - Return the first EnumConstantDecl in the enum. - /// - EnumConstantDecl *getEnumConstantList() { - return cast_or_null(getDeclChain()); - } - const EnumConstantDecl *getEnumConstantList() const { - return cast_or_null(getDeclChain()); - } - + static bool classof(const Decl *D) { return D->getKind() == Enum; } static bool classof(const EnumDecl *D) { return true; } static DeclContext *castToDeclContext(const EnumDecl *D) { @@ -957,16 +970,12 @@ protected: /// union Y { int A, B; }; // Has body with members A and B (FieldDecls). /// This decl will be marked invalid if *any* members are invalid. /// -class RecordDecl : public TagDecl { +class RecordDecl : public TagDecl, public DeclContext { /// HasFlexibleArrayMember - This is true if this struct ends with a flexible /// array member (e.g. int X[]) or if this union contains a struct that does. /// If so, this cannot be contained in arrays or other structs as a member. bool HasFlexibleArrayMember : 1; - /// Members/NumMembers - This is a new[]'d array of pointers to Decls. - FieldDecl **Members; // Null if not defined. - int NumMembers; // -1 if not defined. - protected: RecordDecl(Kind DK, TagKind TK, DeclContext *DC, SourceLocation L, IdentifierInfo *Id); @@ -993,42 +1002,74 @@ public: return cast_or_null(TagDecl::getDefinition(C)); } - /// getNumMembers - Return the number of members, or -1 if this is a forward - /// definition. - int getNumMembers() const { return NumMembers; } - const FieldDecl *getMember(unsigned i) const { return Members[i]; } - FieldDecl *getMember(unsigned i) { return Members[i]; } - // Iterator access to field members. - typedef FieldDecl **field_iterator; - typedef FieldDecl * const *field_const_iterator; + class field_iterator { + /// Current - Current position within the sequence of declarations + /// in this record. + DeclContext::decl_iterator Current; + + /// End - Last position in the sequence of declarations in this + /// record. + DeclContext::decl_iterator End; + + /// SkipToNextField - Advances the current position up to the next + /// FieldDecl. + void SkipToNextField() { + while (Current != End && !isa(*Current)) + ++Current; + } - field_iterator field_begin() { - assert(isDefinition() && "Not a definition!"); - return Members; - } - field_iterator field_end() { - assert(isDefinition() && "Not a definition!"); - return Members + getNumMembers(); - } + public: + typedef FieldDecl* value_type; + typedef FieldDecl* reference; + typedef FieldDecl* pointer; + typedef std::ptrdiff_t difference_type; + typedef std::forward_iterator_tag iterator_category; + + field_iterator() : Current(), End() { } + + field_iterator(DeclContext::decl_iterator C, DeclContext::decl_iterator E) + : Current(C), End(E) { + SkipToNextField(); + } + + reference operator*() const { return cast(*Current); } - field_const_iterator field_begin() const { - assert(isDefinition() && "Not a definition!"); - return Members; + pointer operator->() const { return cast(*Current); } + + field_iterator& operator++() { + ++Current; + SkipToNextField(); + return *this; + } + + field_iterator operator++(int) { + field_iterator tmp(*this); + ++(*this); + return tmp; + } + + friend bool operator==(const field_iterator& x, const field_iterator& y) { + return x.Current == y.Current; + } + + friend bool operator!=(const field_iterator& x, const field_iterator& y) { + return x.Current != y.Current; + } + }; + + typedef field_iterator field_const_iterator; + + field_iterator field_begin() const { + return field_iterator(decls_begin(), decls_end()); } - field_const_iterator field_end() const { - assert(isDefinition() && "Not a definition!"); - return Members + getNumMembers(); + field_iterator field_end() const { + return field_iterator(decls_end(), decls_end()); } - /// defineBody - When created, RecordDecl's correspond to a forward declared - /// record. This method is used to mark the decl as being defined, with the - /// specified contents. - void defineBody(ASTContext& C, FieldDecl **Members, unsigned numMembers); - - /// getMember - If the member doesn't exist, or there are no members, this - /// function will return 0; - FieldDecl *getMember(IdentifierInfo *name); + /// completeDefinition - Notes that the definition of this type is + /// now complete. + void completeDefinition(ASTContext& C); static bool classof(const Decl *D) { return D->getKind() >= RecordFirst && D->getKind() <= RecordLast; diff --git a/include/clang/AST/DeclBase.h b/include/clang/AST/DeclBase.h index 55919da54e..badf6345ec 100644 --- a/include/clang/AST/DeclBase.h +++ b/include/clang/AST/DeclBase.h @@ -17,11 +17,14 @@ #include "clang/AST/Attr.h" #include "clang/AST/Type.h" #include "clang/Basic/SourceLocation.h" +#include "llvm/ADT/PointerIntPair.h" +#include namespace clang { class DeclContext; class TranslationUnitDecl; class NamespaceDecl; +class NamedDecl; class ScopedDecl; class FunctionDecl; class CXXRecordDecl; @@ -29,6 +32,7 @@ class EnumDecl; class ObjCMethodDecl; class ObjCInterfaceDecl; class BlockDecl; +class DeclarationName; /// Decl - This represents one declaration (or definition), e.g. a variable, /// typedef, function, struct, etc. @@ -44,10 +48,6 @@ public: // Decl TranslationUnit, // [DeclContext] // NamedDecl - Field, - CXXField, - ObjCIvar, - ObjCAtDefsField, OverloadedFunction, ObjCCategory, ObjCCategoryImpl, @@ -56,13 +56,16 @@ public: ObjCProtocol, ObjCProperty, // ScopedDecl + Field, + ObjCIvar, + ObjCAtDefsField, Namespace, // [DeclContext] // TypeDecl Typedef, // TagDecl Enum, // [DeclContext] - Record, - CXXRecord, // [DeclContext] + Record, // [DeclContext] + CXXRecord, TemplateTypeParm, // ValueDecl EnumConstant, @@ -87,9 +90,9 @@ public: // For each non-leaf class, we now define a mapping to the first/last member // of the class, to allow efficient classof. - NamedFirst = Field , NamedLast = NonTypeTemplateParm, + NamedFirst = OverloadedFunction , NamedLast = NonTypeTemplateParm, FieldFirst = Field , FieldLast = ObjCAtDefsField, - ScopedFirst = Namespace , ScopedLast = NonTypeTemplateParm, + ScopedFirst = Field , ScopedLast = NonTypeTemplateParm, TypeFirst = Typedef , TypeLast = TemplateTypeParm, TagFirst = Enum , TagLast = CXXRecord, RecordFirst = Record , RecordLast = CXXRecord, @@ -183,10 +186,10 @@ public: case ParmVar: case EnumConstant: case NonTypeTemplateParm: + case Field: case ObjCInterface: case ObjCCompatibleAlias: case OverloadedFunction: - case CXXField: case CXXMethod: case CXXConversion: case CXXClassVar: @@ -247,7 +250,7 @@ protected: /// TranslationUnitDecl /// NamespaceDecl /// FunctionDecl -/// CXXRecordDecl +/// RecordDecl/CXXRecordDecl /// EnumDecl /// ObjCMethodDecl /// ObjCInterfaceDecl @@ -257,9 +260,26 @@ class DeclContext { /// DeclKind - This indicates which class this is. Decl::Kind DeclKind : 8; - /// DeclChain - Linked list of declarations that are defined inside this - /// declaration context. - ScopedDecl *DeclChain; + /// LookupPtrKind - Describes what kind of pointer LookupPtr + /// actually is. + enum LookupPtrKind { + /// LookupIsMap - Indicates that LookupPtr is actually a + /// DenseMap pointer. + LookupIsMap = 7 + }; + + /// LookupPtr - Pointer to a data structure used to lookup + /// declarations within this context. If the context contains fewer + /// than seven declarations, the number of declarations is provided + /// in the 3 lowest-order bits and the upper bits are treated as a + /// pointer to an array of NamedDecl pointers. If the context + /// contains seven or more declarations, the upper bits are treated + /// as a pointer to a DenseMap. + llvm::PointerIntPair LookupPtr; + + /// Decls - Contains all of the declarations that are defined inside + /// this declaration context. + std::vector Decls; // Used in the CastTo template to get the DeclKind // from a Decl or a DeclContext. DeclContext doesn't have a getKind() method @@ -281,6 +301,8 @@ class DeclContext { return static_cast(const_cast(D)); case Decl::Enum: return static_cast(const_cast(D)); + case Decl::Record: + return static_cast(const_cast(D)); case Decl::CXXRecord: return static_cast(const_cast(D)); case Decl::ObjCMethod: @@ -296,10 +318,19 @@ class DeclContext { } } + /// isLookupMap - Determine if the lookup structure is a + /// DenseMap. Othewise, it is an array. + bool isLookupMap() const { return LookupPtr.getInt() == LookupIsMap; } + protected: - DeclContext(Decl::Kind K) : DeclKind(K), DeclChain(0) {} + DeclContext(Decl::Kind K) : DeclKind(K), LookupPtr() { + } + + void DestroyDecls(ASTContext &C); public: + ~DeclContext(); + /// getParent - Returns the containing DeclContext if this is a ScopedDecl, /// else returns NULL. const DeclContext *getParent() const; @@ -309,12 +340,12 @@ public: } /// getLexicalParent - Returns the containing lexical DeclContext. May be - /// different from getParent, e.g.: - /// - /// namespace A { - /// struct S; - /// } - /// struct A::S {}; // getParent() == namespace 'A' + /// different from getParent, e.g.: + /// + /// namespace A { + /// struct S; + /// } + /// struct A::S {}; // getParent() == namespace 'A' /// // getLexicalParent() == translation unit /// const DeclContext *getLexicalParent() const; @@ -326,11 +357,12 @@ public: bool isFunctionOrMethod() const { switch (DeclKind) { case Decl::Block: - case Decl::Function: - case Decl::CXXMethod: case Decl::ObjCMethod: return true; + default: + if (DeclKind >= Decl::FunctionFirst && DeclKind <= Decl::FunctionLast) + return true; return false; } } @@ -343,6 +375,10 @@ public: return DeclKind == Decl::CXXRecord; } + bool isNamespace() const { + return DeclKind == Decl::Namespace; + } + bool Encloses(DeclContext *DC) const { for (; DC; DC = DC->getParent()) if (DC == this) @@ -350,15 +386,105 @@ public: return false; } - const ScopedDecl *getDeclChain() const { return DeclChain; } - ScopedDecl *getDeclChain() { return DeclChain; } - void setDeclChain(ScopedDecl *D) { DeclChain = D; } + /// getPrimaryContext - There may be many different + /// declarations of the same entity (including forward declarations + /// of classes, multiple definitions of namespaces, etc.), each with + /// a different set of declarations. This routine returns the + /// "primary" DeclContext structure, which will contain the + /// information needed to perform name lookup into this context. + DeclContext *getPrimaryContext(ASTContext &Context); + + /// getNextContext - If this is a DeclContext that may have other + /// DeclContexts that are semantically connected but syntactically + /// different, such as C++ namespaces, this routine retrieves the + /// next DeclContext in the link. Iteration through the chain of + /// DeclContexts should begin at the primary DeclContext and + /// continue until this function returns NULL. For example, given: + /// @code + /// namespace N { + /// int x; + /// } + /// namespace N { + /// int y; + /// } + /// @endcode + /// The first occurrence of namespace N will be the primary + /// DeclContext. Its getNextContext will return the second + /// occurrence of namespace N. + DeclContext *getNextContext(); + + /// decl_iterator - Iterates through the declarations stored + /// within this context. + typedef std::vector::const_iterator decl_iterator; + + /// reverse_decl_iterator - Iterates through the declarations stored + /// within this context in reverse order. + typedef std::vector::const_reverse_iterator + reverse_decl_iterator; + + /// decls_begin/decls_end - Iterate over the declarations stored in + /// this context. + decl_iterator decls_begin() const { return Decls.begin(); } + decl_iterator decls_end() const { return Decls.end(); } + + /// decls_rbegin/decls_rend - Iterate over the declarations stored + /// in this context in reverse order. + reverse_decl_iterator decls_rbegin() const { return Decls.rbegin(); } + reverse_decl_iterator decls_rend() const { return Decls.rend(); } + + /// addDecl - Add the declaration D to this scope. Note that + /// declarations are added at the beginning of the declaration + /// chain, so reverseDeclChain() should be called after all + /// declarations have been added. If AllowLookup, also adds this + /// declaration into data structure for name lookup. + void addDecl(ASTContext &Context, ScopedDecl *D, bool AllowLookup = true); + + /// reverseDeclChain - Reverse the chain of declarations stored in + /// this scope. Typically called once after all declarations have + /// been added and the scope is closed. + void reverseDeclChain(); + + /// lookup_iterator - An iterator that provides access to the results + /// of looking up a name within this context. + typedef NamedDecl **lookup_iterator; + + /// lookup_const_iterator - An iterator that provides non-mutable + /// access to the results of lookup up a name within this context. + typedef NamedDecl * const * lookup_const_iterator; + + typedef std::pair lookup_result; + typedef std::pair + lookup_const_result; + + /// lookup - Find the declarations (if any) with the given Name in + /// this context. Returns a range of iterators that contains all of + /// the declarations with this name (which may be 0, 1, or 2 + /// declarations). If two declarations are returned, the declaration + /// in the "ordinary" identifier namespace will precede the + /// declaration in the "tag" identifier namespace (e.g., values + /// before types). Note that this routine will not look into parent + /// contexts. + lookup_result lookup(ASTContext &Context, DeclarationName Name); + lookup_const_result lookup(ASTContext &Context, DeclarationName Name) const; + + /// insert - Insert the declaration D into this context. Up to two + /// declarations with the same name can be inserted into a single + /// declaration context, one in the "tag" namespace (e.g., for + /// classes and enums) and one in the "ordinary" namespaces (e.g., + /// for variables, functions, and other values). Note that, if there + /// is already a declaration with the same name and identifier + /// namespace, D will replace it. It is up to the caller to ensure + /// that this replacement is semantically correct, e.g., that + /// declarations are only replaced by later declarations of the same + /// entity and not a declaration of some other kind of entity. + void insert(ASTContext &Context, NamedDecl *D); static bool classof(const Decl *D) { switch (D->getKind()) { case Decl::TranslationUnit: case Decl::Namespace: case Decl::Enum: + case Decl::Record: case Decl::CXXRecord: case Decl::ObjCMethod: case Decl::ObjCInterface: @@ -375,6 +501,7 @@ public: static bool classof(const TranslationUnitDecl *D) { return true; } static bool classof(const NamespaceDecl *D) { return true; } static bool classof(const FunctionDecl *D) { return true; } + static bool classof(const RecordDecl *D) { return true; } static bool classof(const CXXRecordDecl *D) { return true; } static bool classof(const EnumDecl *D) { return true; } static bool classof(const ObjCMethodDecl *D) { return true; } @@ -382,6 +509,8 @@ public: static bool classof(const BlockDecl *D) { return true; } private: + void insertImpl(NamedDecl *D); + void EmitOutRec(llvm::Serializer& S) const; void ReadOutRec(llvm::Deserializer& D, ASTContext& C); @@ -430,6 +559,20 @@ struct cast_convert_val< ::clang::DeclContext, FromTy*, FromTy*> { } }; +template +struct cast_convert_val< const ::clang::DeclContext, FromTy, FromTy> { + static const ::clang::DeclContext &doit(const FromTy &Val) { + return *FromTy::castToDeclContext(&Val); + } +}; + +template +struct cast_convert_val< const ::clang::DeclContext, FromTy*, FromTy*> { + static const ::clang::DeclContext *doit(const FromTy *Val) { + return FromTy::castToDeclContext(Val); + } +}; + /// Implement cast_convert_val for DeclContext -> Decl conversions. template struct cast_convert_valgetDeclContext() == getDeclContext())) && - "Overloaded functions must all be in the same context"); assert((FD->getDeclName() == getDeclName() || isa(FD) || isa(FD)) && "Overloaded functions must have the same name"); @@ -173,29 +171,6 @@ protected: friend class CXXRecordDecl; }; -/// CXXFieldDecl - Represents an instance field of a C++ struct/union/class. -class CXXFieldDecl : public FieldDecl { - CXXRecordDecl *Parent; - bool Mutable; - - CXXFieldDecl(CXXRecordDecl *RD, SourceLocation L, IdentifierInfo *Id, - QualType T, bool Mut, Expr *BW = NULL) - : FieldDecl(CXXField, L, Id, T, BW), Parent(RD), Mutable(Mut) {} -public: - static CXXFieldDecl *Create(ASTContext &C, CXXRecordDecl *RD,SourceLocation L, - IdentifierInfo *Id, QualType T, bool Mut, - Expr *BW = NULL); - - void setAccess(AccessSpecifier AS) { Access = AS; } - AccessSpecifier getAccess() const { return AccessSpecifier(Access); } - CXXRecordDecl *getParent() const { return Parent; } - bool isMutable() const { return Mutable; } - - // Implement isa/cast/dyncast/etc. - static bool classof(const Decl *D) { return D->getKind() == CXXField; } - static bool classof(const CXXFieldDecl *D) { return true; } -}; - /// CXXBaseSpecifier - A base class of a C++ class. /// /// Each CXXBaseSpecifier represents a single, direct base class (or @@ -277,11 +252,9 @@ public: }; /// CXXRecordDecl - Represents a C++ struct/union/class. -/// CXXRecordDecl differs from RecordDecl in several ways. First, it -/// is a DeclContext, because it can contain other -/// declarations. Second, it provides additional C++ fields, including -/// storage for base classes and constructors. -class CXXRecordDecl : public RecordDecl, public DeclContext { +/// FIXME: This class will disappear once we've properly taught RecordDecl +/// to deal with C++-specific things. +class CXXRecordDecl : public RecordDecl { /// UserDeclaredConstructor - True when this class has a /// user-declared constructor. bool UserDeclaredConstructor : 1; @@ -348,19 +321,6 @@ public: base_class_iterator bases_end() { return Bases + NumBases; } base_class_const_iterator bases_end() const { return Bases + NumBases; } - const CXXFieldDecl *getMember(unsigned i) const { - return cast(RecordDecl::getMember(i)); - } - CXXFieldDecl *getMember(unsigned i) { - return cast(RecordDecl::getMember(i)); - } - - /// getMember - If the member doesn't exist, or there are no members, this - /// function will return 0; - CXXFieldDecl *getMember(IdentifierInfo *name) { - return cast_or_null(RecordDecl::getMember(name)); - } - /// getConstructors - Retrieve the overload set containing all of /// the constructors of this class. OverloadedFunctionDecl *getConstructors() { return &Constructors; } @@ -537,7 +497,7 @@ protected: class CXXBaseOrMemberInitializer { /// BaseOrMember - This points to the entity being initialized, /// which is either a base class (a Type) or a non-static data - /// member (a CXXFieldDecl). When the low bit is 1, it's a base + /// member. When the low bit is 1, it's a base /// class; when the low bit is 0, it's a member. uintptr_t BaseOrMember; @@ -552,7 +512,7 @@ public: /// CXXBaseOrMemberInitializer - Creates a new member initializer. explicit - CXXBaseOrMemberInitializer(CXXFieldDecl *Member, Expr **Args, unsigned NumArgs); + CXXBaseOrMemberInitializer(FieldDecl *Member, Expr **Args, unsigned NumArgs); /// ~CXXBaseOrMemberInitializer - Destroy the base or member initializer. ~CXXBaseOrMemberInitializer(); @@ -598,9 +558,9 @@ public: /// getMember - If this is a member initializer, returns the /// declaration of the non-static data member being /// initialized. Otherwise, returns NULL. - CXXFieldDecl *getMember() { + FieldDecl *getMember() { if (isMemberInitializer()) - return reinterpret_cast(BaseOrMember); + return reinterpret_cast(BaseOrMember); else return 0; } @@ -917,14 +877,14 @@ public: if (ScopedDecl *SD = dyn_cast(MD)) { return cast(SD->getDeclContext()); } - return cast(MD)->getParent(); + return cast(cast(MD)->getDeclContext()); } static bool isMember(Decl *D) { if (ScopedDecl *SD = dyn_cast(D)) { return isa(SD->getDeclContext()); } - return isa(D); + return isa(D); } }; diff --git a/include/clang/AST/DeclObjC.h b/include/clang/AST/DeclObjC.h index 81f8f61120..00e51783af 100644 --- a/include/clang/AST/DeclObjC.h +++ b/include/clang/AST/DeclObjC.h @@ -506,7 +506,8 @@ public: private: ObjCIvarDecl(SourceLocation L, IdentifierInfo *Id, QualType T, AccessControl ac, Expr *BW) - : FieldDecl(ObjCIvar, L, Id, T, BW), DeclAccess(ac) {} + : FieldDecl(ObjCIvar, 0, L, Id, T, BW, /*Mutable=*/false, 0), + DeclAccess(ac) {} public: static ObjCIvarDecl *Create(ASTContext &C, SourceLocation L, @@ -534,12 +535,13 @@ private: /// @defs(...). class ObjCAtDefsFieldDecl : public FieldDecl { private: - ObjCAtDefsFieldDecl(SourceLocation L, IdentifierInfo *Id, + ObjCAtDefsFieldDecl(DeclContext *DC, SourceLocation L, IdentifierInfo *Id, QualType T, Expr *BW) - : FieldDecl(ObjCAtDefsField, L, Id, T, BW) {} + : FieldDecl(ObjCAtDefsField, DC, L, Id, T, BW, /*Mutable=*/false, 0) {} public: - static ObjCAtDefsFieldDecl *Create(ASTContext &C, SourceLocation L, + static ObjCAtDefsFieldDecl *Create(ASTContext &C, DeclContext *DC, + SourceLocation L, IdentifierInfo *Id, QualType T, Expr *BW); diff --git a/include/clang/AST/DeclarationName.h b/include/clang/AST/DeclarationName.h index f387d69986..8aac8ac00d 100644 --- a/include/clang/AST/DeclarationName.h +++ b/include/clang/AST/DeclarationName.h @@ -198,6 +198,10 @@ public: /// name as an opaque integer. uintptr_t getAsOpaqueInteger() const { return Ptr; } + /// getAsOpaquePtr - Get the representation of this declaration name as + /// an opaque pointer. + void *getAsOpaquePtr() const { return reinterpret_cast(Ptr); } + static DeclarationName getFromOpaqueInteger(uintptr_t P) { DeclarationName N; N.Ptr = P; diff --git a/include/clang/Parse/Action.h b/include/clang/Parse/Action.h index a39ebc9d4b..991bd49fe9 100644 --- a/include/clang/Parse/Action.h +++ b/include/clang/Parse/Action.h @@ -265,10 +265,10 @@ public: /// Act on @defs() element found when parsing a structure. ClassName is the /// name of the referenced class. - virtual void ActOnDefs(Scope *S, SourceLocation DeclStart, + virtual void ActOnDefs(Scope *S, DeclTy *TagD, SourceLocation DeclStart, IdentifierInfo *ClassName, llvm::SmallVectorImpl &Decls) {} - virtual DeclTy *ActOnField(Scope *S, SourceLocation DeclStart, + virtual DeclTy *ActOnField(Scope *S, DeclTy *TagD, SourceLocation DeclStart, Declarator &D, ExprTy *BitfieldWidth) { return 0; } diff --git a/include/clang/Parse/Scope.h b/include/clang/Parse/Scope.h index f8815ffd4f..ef5f877abb 100644 --- a/include/clang/Parse/Scope.h +++ b/include/clang/Parse/Scope.h @@ -112,6 +112,12 @@ private: typedef llvm::SmallPtrSet DeclSetTy; DeclSetTy DeclsInScope; + /// Entity - The entity with which this scope is associated. For + /// example, the entity of a class scope is the class itself, the + /// entity of a function scope is a function, etc. This field is + /// maintained by the Action implementation. + void *Entity; + public: Scope(Scope *Parent, unsigned ScopeFlags) { Init(Parent, ScopeFlags); @@ -178,12 +184,19 @@ public: DeclsInScope.insert(D); } + void RemoveDecl(Action::DeclTy *D) { + DeclsInScope.erase(D); + } + /// isDeclScope - Return true if this is the scope that the specified decl is /// declared in. bool isDeclScope(Action::DeclTy *D) { return DeclsInScope.count(D) != 0; } + void* getEntity() const { return Entity; } + void setEntity(void *E) { Entity = E; } + /// isCXXClassScope - Return true if this scope is a C++ class scope. bool isCXXClassScope() const { return (getFlags() & Scope::CXXClassScope); @@ -242,6 +255,7 @@ public: if (Flags & BlockScope) BlockParent = this; if (Flags & TemplateParamScope) TemplateParamParent = this; DeclsInScope.clear(); + Entity = 0; } }; diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index 044106300c..3455504fdb 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -539,7 +539,7 @@ const ASTRecordLayout &ASTContext::getASTRecordLayout(const RecordDecl *D) { ASTRecordLayout *NewEntry = new ASTRecordLayout(); Entry = NewEntry; - NewEntry->InitializeLayout(D->getNumMembers()); + NewEntry->InitializeLayout(std::distance(D->field_begin(), D->field_end())); bool IsUnion = D->isUnion(); unsigned StructPacking = 0; @@ -552,10 +552,11 @@ const ASTRecordLayout &ASTContext::getASTRecordLayout(const RecordDecl *D) { // Layout each field, for now, just sequentially, respecting alignment. In // the future, this will need to be tweakable by targets. - for (unsigned i = 0, e = D->getNumMembers(); i != e; ++i) { - const FieldDecl *FD = D->getMember(i); - NewEntry->LayoutField(FD, i, IsUnion, StructPacking, *this); - } + unsigned FieldIdx = 0; + for (RecordDecl::field_iterator Field = D->field_begin(), + FieldEnd = D->field_end(); + Field != FieldEnd; (void)++Field, ++FieldIdx) + NewEntry->LayoutField(*Field, FieldIdx, IsUnion, StructPacking, *this); // Finally, round the size of the total struct up to the alignment of the // struct itself. @@ -996,12 +997,16 @@ QualType ASTContext::getTypeDeclType(TypeDecl *Decl, TypeDecl* PrevDecl) { return QualType(Decl->TypeForDecl, 0); } -/// setTagDefinition - Used by RecordDecl::defineBody to inform ASTContext -/// about which RecordDecl serves as the definition of a particular -/// struct/union/class. This will eventually be used by enums as well. +/// setTagDefinition - Used by RecordDecl::completeDefinition and +/// EnumDecl::completeDefinition to inform about which +/// RecordDecl/EnumDecl serves as the definition of a particular +/// struct/union/class/enum. void ASTContext::setTagDefinition(TagDecl* D) { assert (D->isDefinition()); - cast(D->TypeForDecl)->decl = D; + if (!D->TypeForDecl) + getTypeDeclType(D); + else + cast(D->TypeForDecl)->decl = D; } /// getTypedefType - Return the unique reference to the type for the @@ -1460,14 +1465,17 @@ QualType ASTContext::getCFConstantStringType() { FieldTypes[2] = getPointerType(CharTy.getQualifiedType(QualType::Const)); // long length; FieldTypes[3] = LongTy; - // Create fields - FieldDecl *FieldDecls[4]; - - for (unsigned i = 0; i < 4; ++i) - FieldDecls[i] = FieldDecl::Create(*this, SourceLocation(), 0, - FieldTypes[i]); - CFConstantStringTypeDecl->defineBody(*this, FieldDecls, 4); + // Create fields + for (unsigned i = 0; i < 4; ++i) { + FieldDecl *Field = FieldDecl::Create(*this, CFConstantStringTypeDecl, + SourceLocation(), 0, + FieldTypes[i], /*BitWidth=*/0, + /*Mutable=*/false, /*PrevDecl=*/0); + CFConstantStringTypeDecl->addDecl(*this, Field, true); + } + + CFConstantStringTypeDecl->completeDefinition(*this); } return getTagDeclType(CFConstantStringTypeDecl); @@ -1476,6 +1484,10 @@ QualType ASTContext::getCFConstantStringType() { QualType ASTContext::getObjCFastEnumerationStateType() { if (!ObjCFastEnumerationStateTypeDecl) { + ObjCFastEnumerationStateTypeDecl = + RecordDecl::Create(*this, TagDecl::TK_struct, TUDecl, SourceLocation(), + &Idents.get("__objcFastEnumerationState")); + QualType FieldTypes[] = { UnsignedLongTy, getPointerType(ObjCIdType), @@ -1484,16 +1496,16 @@ QualType ASTContext::getObjCFastEnumerationStateType() llvm::APInt(32, 5), ArrayType::Normal, 0) }; - FieldDecl *FieldDecls[4]; - for (size_t i = 0; i < 4; ++i) - FieldDecls[i] = FieldDecl::Create(*this, SourceLocation(), 0, - FieldTypes[i]); - - ObjCFastEnumerationStateTypeDecl = - RecordDecl::Create(*this, TagDecl::TK_struct, TUDecl, SourceLocation(), - &Idents.get("__objcFastEnumerationState")); + for (size_t i = 0; i < 4; ++i) { + FieldDecl *Field = FieldDecl::Create(*this, + ObjCFastEnumerationStateTypeDecl, + SourceLocation(), 0, + FieldTypes[i], /*BitWidth=*/0, + /*Mutable=*/false, /*PrevDecl=*/0); + ObjCFastEnumerationStateTypeDecl->addDecl(*this, Field, true); + } - ObjCFastEnumerationStateTypeDecl->defineBody(*this, FieldDecls, 4); + ObjCFastEnumerationStateTypeDecl->completeDefinition(*this); } return getTagDeclType(ObjCFastEnumerationStateTypeDecl); @@ -1745,16 +1757,17 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S, } if (ExpandStructures) { S += '='; - for (int i = 0; i < RDecl->getNumMembers(); i++) { - FieldDecl *FD = RDecl->getMember(i); + for (RecordDecl::field_iterator Field = RDecl->field_begin(), + FieldEnd = RDecl->field_end(); + Field != FieldEnd; ++Field) { if (NameFields) { S += '"'; - S += FD->getNameAsString(); + S += Field->getNameAsString(); S += '"'; } // Special case bit-fields. - if (const Expr *E = FD->getBitWidth()) { + if (const Expr *E = Field->getBitWidth()) { // FIXME: Fix constness. ASTContext *Ctx = const_cast(this); unsigned N = E->getIntegerConstantExprValue(*Ctx).getZExtValue(); @@ -1763,7 +1776,8 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S, S += 'b'; S += llvm::utostr(N); } else { - getObjCEncodingForTypeImpl(FD->getType(), S, false, true, NameFields); + getObjCEncodingForTypeImpl(Field->getType(), S, false, true, + NameFields); } } } diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index 194f47f96c..7643e4eda8 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -81,10 +81,11 @@ BlockDecl *BlockDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L) { return new (Mem) BlockDecl(DC, L); } -FieldDecl *FieldDecl::Create(ASTContext &C, SourceLocation L, - IdentifierInfo *Id, QualType T, Expr *BW) { +FieldDecl *FieldDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L, + IdentifierInfo *Id, QualType T, Expr *BW, + bool Mutable, ScopedDecl *PrevDecl) { void *Mem = C.getAllocator().Allocate(); - return new (Mem) FieldDecl(L, Id, T, BW); + return new (Mem) FieldDecl(Decl::Field, DC, L, Id, T, BW, Mutable, PrevDecl); } @@ -118,10 +119,21 @@ EnumDecl *EnumDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L, } void EnumDecl::Destroy(ASTContext& C) { - if (getEnumConstantList()) getEnumConstantList()->Destroy(C); + DeclContext::DestroyDecls(C); Decl::Destroy(C); } +void EnumDecl::completeDefinition(ASTContext &C, QualType NewType) { + assert(!isDefinition() && "Cannot redefine enums!"); + setDefinition(true); + + IntegerType = NewType; + + // Let ASTContext know that this is the defining EnumDecl for this + // type. + C.setTagDefinition(this); +} + FileScopeAsmDecl *FileScopeAsmDecl::Create(ASTContext &C, SourceLocation L, StringLiteral *Str) { @@ -248,12 +260,10 @@ TagDecl* TagDecl::getDefinition(ASTContext& C) const { RecordDecl::RecordDecl(Kind DK, TagKind TK, DeclContext *DC, SourceLocation L, IdentifierInfo *Id) -: TagDecl(DK, TK, DC, L, Id, 0) { + : TagDecl(DK, TK, DC, L, Id, 0), DeclContext(DK) { HasFlexibleArrayMember = false; assert(classof(static_cast(this)) && "Invalid Kind!"); - Members = 0; - NumMembers = -1; } RecordDecl *RecordDecl::Create(ASTContext &C, TagKind TK, DeclContext *DC, @@ -267,46 +277,25 @@ RecordDecl *RecordDecl::Create(ASTContext &C, TagKind TK, DeclContext *DC, } RecordDecl::~RecordDecl() { - delete[] Members; } void RecordDecl::Destroy(ASTContext& C) { - if (isDefinition()) - for (field_iterator I=field_begin(), E=field_end(); I!=E; ++I) - (*I)->Destroy(C); - + DeclContext::DestroyDecls(C); TagDecl::Destroy(C); } -/// defineBody - When created, RecordDecl's correspond to a forward declared -/// record. This method is used to mark the decl as being defined, with the -/// specified contents. -void RecordDecl::defineBody(ASTContext& C, FieldDecl **members, - unsigned numMembers) { +/// completeDefinition - Notes that the definition of this type is now +/// complete. +void RecordDecl::completeDefinition(ASTContext& C) { assert(!isDefinition() && "Cannot redefine record!"); + setDefinition(true); - NumMembers = numMembers; - if (numMembers) { - Members = new FieldDecl*[numMembers]; - memcpy(Members, members, numMembers*sizeof(Decl*)); - } - // Let ASTContext know that this is the defining RecordDecl this type. + // Let ASTContext know that this is the defining RecordDecl for this + // type. C.setTagDefinition(this); } - -FieldDecl *RecordDecl::getMember(IdentifierInfo *II) { - if (Members == 0 || NumMembers < 0) - return 0; - - // Linear search. When C++ classes come along, will likely need to revisit. - for (int i = 0; i != NumMembers; ++i) - if (Members[i]->getIdentifier() == II) - return Members[i]; - return 0; -} - //===----------------------------------------------------------------------===// // BlockDecl Implementation //===----------------------------------------------------------------------===// diff --git a/lib/AST/DeclBase.cpp b/lib/AST/DeclBase.cpp index 7b5df1c194..3e0f158cbe 100644 --- a/lib/AST/DeclBase.cpp +++ b/lib/AST/DeclBase.cpp @@ -15,6 +15,7 @@ #include "clang/AST/DeclObjC.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/ASTContext.h" +#include "clang/AST/Type.h" #include "llvm/ADT/DenseMap.h" using namespace clang; @@ -34,7 +35,6 @@ static unsigned nNamespaces = 0; static unsigned nOverFuncs = 0; static unsigned nTypedef = 0; static unsigned nFieldDecls = 0; -static unsigned nCXXFieldDecls = 0; static unsigned nInterfaceDecls = 0; static unsigned nClassDecls = 0; static unsigned nMethodDecls = 0; @@ -95,7 +95,7 @@ bool Decl::CollectingStats(bool Enable) { void Decl::PrintStats() { fprintf(stderr, "*** Decl Stats:\n"); fprintf(stderr, " %d decls total.\n", - int(nFuncs+nVars+nParmVars+nFieldDecls+nSUC+nCXXFieldDecls+nCXXSUC+ + int(nFuncs+nVars+nParmVars+nFieldDecls+nSUC+nCXXSUC+ nEnumDecls+nEnumConst+nTypedef+nInterfaceDecls+nClassDecls+ nMethodDecls+nProtocolDecls+nCategoryDecls+nIvarDecls+ nAtDefsFieldDecls+nNamespaces+nOverFuncs)); @@ -122,9 +122,6 @@ void Decl::PrintStats() { fprintf(stderr, " %d struct/union/class decls, %d each (%d bytes)\n", nSUC, (int)sizeof(RecordDecl), int(nSUC*sizeof(RecordDecl))); - fprintf(stderr, " %d C++ field decls, %d each (%d bytes)\n", - nCXXFieldDecls, (int)sizeof(CXXFieldDecl), - int(nCXXFieldDecls*sizeof(CXXFieldDecl))); fprintf(stderr, " %d C++ struct/union/class decls, %d each (%d bytes)\n", nCXXSUC, (int)sizeof(CXXRecordDecl), int(nCXXSUC*sizeof(CXXRecordDecl))); @@ -183,7 +180,7 @@ void Decl::PrintStats() { int(nFuncs*sizeof(FunctionDecl)+ nVars*sizeof(VarDecl)+nParmVars*sizeof(ParmVarDecl)+ nFieldDecls*sizeof(FieldDecl)+nSUC*sizeof(RecordDecl)+ - nCXXFieldDecls*sizeof(CXXFieldDecl)+nCXXSUC*sizeof(CXXRecordDecl)+ + nCXXSUC*sizeof(CXXRecordDecl)+ nEnumDecls*sizeof(EnumDecl)+nEnumConst*sizeof(EnumConstantDecl)+ nTypedef*sizeof(TypedefDecl)+ nInterfaceDecls*sizeof(ObjCInterfaceDecl)+ @@ -236,7 +233,6 @@ void Decl::addDeclKind(Kind k) { case ImplicitParam: case TranslationUnit: break; - case CXXField: nCXXFieldDecls++; break; case CXXRecord: nCXXSUC++; break; // FIXME: Statistics for C++ decls. case TemplateTypeParm: @@ -372,3 +368,269 @@ const DeclContext *DeclContext::getLexicalParent() const { return SD->getLexicalDeclContext(); return getParent(); } + +/// TwoNamedDecls - Stores up to two NamedDecls. The first +/// declaration, if any, is in the ordinary identifier namespace, and +/// corresponds to values (functions, variables, etc.). The second +/// declaration, if any, is in the tag identifier namespace, and +/// corresponds to tag types (classes, enums). +struct TwoNamedDecls { + NamedDecl* Decls[2]; +}; + +// FIXME: We really want to use a DenseSet here to eliminate the +// redundant storage of the declaration names, but (1) it doesn't give +// us the ability to search based on DeclarationName, (2) we really +// need something more like a DenseMultiSet, and (3) it's +// implemented in terms of DenseMap anyway. +typedef llvm::DenseMap StoredDeclsMap; + +DeclContext::~DeclContext() { + unsigned Size = LookupPtr.getInt(); + if (Size == LookupIsMap) { + StoredDeclsMap *Map = static_cast(LookupPtr.getPointer()); + delete Map; + } else { + NamedDecl **Array = static_cast(LookupPtr.getPointer()); + delete [] Array; + } +} + +void DeclContext::DestroyDecls(ASTContext &C) { + for (decl_iterator D = Decls.begin(); D != Decls.end(); ++D) { + if ((*D)->getLexicalDeclContext() == this) + (*D)->Destroy(C); + } +} + +DeclContext *DeclContext::getPrimaryContext(ASTContext &Context) { + switch (DeclKind) { + case Decl::Block: + case Decl::TranslationUnit: + // There is only one DeclContext for these entities. + return this; + + case Decl::Namespace: + // The original namespace is our primary context. + return static_cast(this)->getOriginalNamespace(); + + case Decl::Enum: + // The declaration associated with the enumeration type is our + // primary context. + return Context.getTypeDeclType(static_cast(this)) + ->getAsEnumType()->getDecl(); + + case Decl::Record: + case Decl::CXXRecord: { + // The declaration associated with the type is be our primary + // context. +#if 0 + // FIXME: This is what we expect to do. However, it doesn't work + // because ASTContext::setTagDefinition changes the result of + // Context.getTypeDeclType, meaning that our "primary" declaration + // of a RecordDecl/CXXRecordDecl will change, and we won't be able + // to find any values inserted into the earlier "primary" + // declaration. We need better tracking of redeclarations and + // definitions. + QualType Type = Context.getTypeDeclType(static_cast(this)); + return Type->getAsRecordType()->getDecl(); +#else + // FIXME: This hack will work for now, because the declaration we + // create when we're defining the record is the one we'll use as + // the definition later. + return this; +#endif + } + + case Decl::ObjCMethod: + return this; + + case Decl::ObjCInterface: + // FIXME: Can Objective-C interfaces be forward-declared? + return this; + + default: + assert(DeclKind >= Decl::FunctionFirst && DeclKind <= Decl::FunctionLast && + "Unknown DeclContext kind"); + return this; + } +} + +DeclContext *DeclContext::getNextContext() { + switch (DeclKind) { + case Decl::Block: + case Decl::TranslationUnit: + case Decl::Enum: + case Decl::Record: + case Decl::CXXRecord: + case Decl::ObjCMethod: + case Decl::ObjCInterface: + // There is only one DeclContext for these entities. + return 0; + + case Decl::Namespace: + // Return the next namespace + return static_cast(this)->getNextNamespace(); + + default: + assert(DeclKind >= Decl::FunctionFirst && DeclKind <= Decl::FunctionLast && + "Unknown DeclContext kind"); + return 0; + } +} + +void DeclContext::addDecl(ASTContext &Context, ScopedDecl *D, bool AllowLookup) { + Decls.push_back(D); + if (AllowLookup) + D->getDeclContext()->insert(Context, D); +} + +DeclContext::lookup_result +DeclContext::lookup(ASTContext &Context, DeclarationName Name) { + DeclContext *PrimaryContext = getPrimaryContext(Context); + if (PrimaryContext != this) + return PrimaryContext->lookup(Context, Name); + + /// If there is no lookup data structure, build one now by talking + /// all of the linked DeclContexts (in declaration order!) and + /// inserting their values. + if (LookupPtr.getPointer() == 0) { + for (DeclContext *DCtx = this; DCtx; DCtx = DCtx->getNextContext()) + for (decl_iterator D = DCtx->decls_begin(); D != DCtx->decls_end(); ++D) + insertImpl(*D); + } + + lookup_result Result(0, 0); + if (isLookupMap()) { + StoredDeclsMap *Map = static_cast(LookupPtr.getPointer()); + StoredDeclsMap::iterator Pos = Map->find(Name); + if (Pos != Map->end()) { + Result.first = Pos->second.Decls[0]? &Pos->second.Decls[0] + : &Pos->second.Decls[1]; + Result.second = Pos->second.Decls[1]? &Pos->second.Decls[2] + : &Pos->second.Decls[1]; + } + return Result; + } + + // We have a small array. Look into it. + unsigned Size = LookupPtr.getInt(); + NamedDecl **Array = static_cast(LookupPtr.getPointer()); + for (unsigned Idx = 0; Idx < Size; ++Idx) + if (Array[Idx]->getDeclName() == Name) { + Result.first = &Array[Idx]; + Result.second = Result.first + 1; + if (Idx + 1 < Size && Array[Idx + 1]->getDeclName() == Name) + ++Result.second; + break; + } + + return Result; +} + +DeclContext::lookup_const_result +DeclContext::lookup(ASTContext &Context, DeclarationName Name) const { + return const_cast(this)->lookup(Context, Name); +} + +void DeclContext::insert(ASTContext &Context, NamedDecl *D) { + DeclContext *PrimaryContext = getPrimaryContext(Context); + if (PrimaryContext != this) { + PrimaryContext->insert(Context, D); + return; + } + + // If we already have a lookup data structure, perform the insertion + // into it. Otherwise, be lazy and don't build that structure until + // someone asks for it. + if (LookupPtr.getPointer()) + insertImpl(D); +} + +void DeclContext::insertImpl(NamedDecl *D) { + if (!isLookupMap()) { + unsigned Size = LookupPtr.getInt(); + + // The lookup data is stored as an array. Search through the array + // to find the insertion location. + NamedDecl **Array; + if (Size == 0) { + Array = new NamedDecl*[LookupIsMap - 1]; + LookupPtr.setPointer(Array); + } else { + Array = static_cast(LookupPtr.getPointer()); + } + + // We always keep declarations of the same name next to each other + // in the array, so that it is easy to return multiple results + // from lookup(). There will be zero, one, or two declarations of + // the same name. + unsigned Match; + for (Match = 0; Match < Size; ++Match) { + if (Array[Match]->getDeclName() == D->getDeclName()) + break; + } + + if (Match < Size) { + // We found another declaration with the same name. If it's also + // in the same identifier namespace, update the declaration in + // place. + Decl::IdentifierNamespace NS = D->getIdentifierNamespace(); + if (Array[Match]->getIdentifierNamespace() == NS) { + Array[Match] = D; + return; + } + if (Match + 1 < Size && Array[Match + 1]->getIdentifierNamespace() == NS) { + Array[Match + 1] = D; + return; + } + + // If there is an existing declaration in the namespace of + // ordinary identifiers, then it must precede the tag + // declaration for C++ name lookup to operate properly. Therefore, + // if our match is an ordinary name and the new name is in the + // tag namespace, we'll insert the new declaration after it. + if (Match < Size && (NS == Decl::IDNS_Tag) && + (Array[Match]->getIdentifierNamespace() & Decl::IDNS_Ordinary)) + ++Match; + } + + if (Size < LookupIsMap - 1) { + // The new declaration will fit in the array. Insert the new + // declaration at the position Match in the array. + for (unsigned Idx = Size; Idx > Match; --Idx) + Array[Idx] = Array[Idx-1]; + + Array[Match] = D; + LookupPtr.setInt(Size + 1); + return; + } + + // We've reached capacity in this array. Create a map and copy in + // all of the declarations that were stored in the array. + StoredDeclsMap *Map = new StoredDeclsMap(16); + LookupPtr.setPointer(Map); + LookupPtr.setInt(LookupIsMap); + for (unsigned Idx = 0; Idx < LookupIsMap - 1; ++Idx) + insertImpl(Array[Idx]); + delete [] Array; + + // Fall through to perform insertion into the map. + } + + // Insert this declaration into the map. + StoredDeclsMap *Map = static_cast(LookupPtr.getPointer()); + StoredDeclsMap::iterator Pos = Map->find(D->getDeclName()); + unsigned IndexOfD = D->getIdentifierNamespace() & Decl::IDNS_Ordinary? 0 : 1; + + if (Pos == Map->end()) { + // Put this declaration into the appropriate slot. + TwoNamedDecls Val; + Val.Decls[0] = 0; + Val.Decls[1] = 0; + Val.Decls[IndexOfD] = D; + Pos = Map->insert(std::make_pair(D->getDeclName(),Val)).first; + } else { + Pos->second.Decls[IndexOfD] = D; + } +} diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp index a26803caec..3eaf301d7a 100644 --- a/lib/AST/DeclCXX.cpp +++ b/lib/AST/DeclCXX.cpp @@ -36,16 +36,9 @@ NonTypeTemplateParmDecl::Create(ASTContext &C, DeclContext *DC, return new (Mem) NonTypeTemplateParmDecl(DC, L, Id, T, TypeSpecStartLoc); } -CXXFieldDecl *CXXFieldDecl::Create(ASTContext &C, CXXRecordDecl *RD, - SourceLocation L, IdentifierInfo *Id, - QualType T, bool Mut, Expr *BW) { - void *Mem = C.getAllocator().Allocate(); - return new (Mem) CXXFieldDecl(RD, L, Id, T, Mut, BW); -} - CXXRecordDecl::CXXRecordDecl(TagKind TK, DeclContext *DC, SourceLocation L, IdentifierInfo *Id) - : RecordDecl(CXXRecord, TK, DC, L, Id), DeclContext(CXXRecord), + : RecordDecl(CXXRecord, TK, DC, L, Id), UserDeclaredConstructor(false), UserDeclaredCopyConstructor(false), Aggregate(true), Polymorphic(false), Bases(0), NumBases(0), Constructors(DC, DeclarationName()), @@ -74,11 +67,6 @@ void CXXRecordDecl::Destroy(ASTContext &C) { if (isDefinition()) Destructor->Destroy(C); - for (OverloadedFunctionDecl::function_iterator func - = Conversions.function_begin(); - func != Conversions.function_end(); ++func) - (*func)->Destroy(C); - RecordDecl::Destroy(C); } @@ -176,7 +164,7 @@ CXXBaseOrMemberInitializer(QualType BaseType, Expr **Args, unsigned NumArgs) } CXXBaseOrMemberInitializer:: -CXXBaseOrMemberInitializer(CXXFieldDecl *Member, Expr **Args, unsigned NumArgs) +CXXBaseOrMemberInitializer(FieldDecl *Member, Expr **Args, unsigned NumArgs) : Args(0), NumArgs(0) { BaseOrMember = reinterpret_cast(Member); assert((BaseOrMember & 0x01) == 0 && "Invalid member pointer"); diff --git a/lib/AST/DeclObjC.cpp b/lib/AST/DeclObjC.cpp index 84f0d98bf2..b9226318e3 100644 --- a/lib/AST/DeclObjC.cpp +++ b/lib/AST/DeclObjC.cpp @@ -95,10 +95,10 @@ ObjCIvarDecl *ObjCIvarDecl::Create(ASTContext &C, SourceLocation L, ObjCAtDefsFieldDecl -*ObjCAtDefsFieldDecl::Create(ASTContext &C, SourceLocation L, +*ObjCAtDefsFieldDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L, IdentifierInfo *Id, QualType T, Expr *BW) { void *Mem = C.getAllocator().Allocate(); - return new (Mem) ObjCAtDefsFieldDecl(L, Id, T, BW); + return new (Mem) ObjCAtDefsFieldDecl(DC, L, Id, T, BW); } void ObjCAtDefsFieldDecl::Destroy(ASTContext& C) { diff --git a/lib/AST/DeclSerialization.cpp b/lib/AST/DeclSerialization.cpp index 29714c0125..c0ffb0c423 100644 --- a/lib/AST/DeclSerialization.cpp +++ b/lib/AST/DeclSerialization.cpp @@ -120,11 +120,29 @@ void Decl::ReadInRec(Deserializer& D, ASTContext& C) { //===----------------------------------------------------------------------===// void DeclContext::EmitOutRec(Serializer& S) const { - S.EmitPtr(DeclChain); + S.EmitInt(Decls.size()); + for (decl_iterator D = decls_begin(); D != decls_end(); ++D) { + bool Owned = ((*D)->getLexicalDeclContext() == this && + DeclKind != Decl::TranslationUnit && + !isFunctionOrMethod()); + S.EmitBool(Owned); + if (Owned) + S.EmitOwnedPtr(*D); + else + S.EmitPtr(*D); + } } void DeclContext::ReadOutRec(Deserializer& D, ASTContext& C) { - D.ReadPtr(DeclChain); + unsigned NumDecls = D.ReadInt(); + Decls.resize(NumDecls); + for (unsigned Idx = 0; Idx < NumDecls; ++Idx) { + bool Owned = D.ReadBool(); + if (Owned) + Decls[Idx] = cast_or_null(D.ReadOwnedPtr(C)); + else + D.ReadPtr(Decls[Idx]); + } } //===----------------------------------------------------------------------===// @@ -205,14 +223,12 @@ void NamedDecl::ReadInRec(Deserializer& D, ASTContext& C) { void ScopedDecl::EmitInRec(Serializer& S) const { NamedDecl::EmitInRec(S); - S.EmitPtr(getNext()); // From ScopedDecl. S.EmitPtr(cast_or_null(getDeclContext())); // From ScopedDecl. S.EmitPtr(cast_or_null(getLexicalDeclContext())); // From ScopedDecl. } void ScopedDecl::ReadInRec(Deserializer& D, ASTContext& C) { NamedDecl::ReadInRec(D, C); - D.ReadPtr(Next); // From ScopedDecl. assert(DeclCtx == 0); @@ -394,8 +410,8 @@ ParmVarDecl* ParmVarDecl::CreateImpl(Deserializer& D, ASTContext& C) { void EnumDecl::EmitImpl(Serializer& S) const { ScopedDecl::EmitInRec(S); S.EmitBool(isDefinition()); - S.Emit(IntegerType); - S.BatchEmitOwnedPtrs(getEnumConstantList(),getNextDeclarator()); + S.Emit(IntegerType); + S.EmitOwnedPtr(getNextDeclarator()); } EnumDecl* EnumDecl::CreateImpl(Deserializer& D, ASTContext& C) { @@ -406,12 +422,7 @@ EnumDecl* EnumDecl::CreateImpl(Deserializer& D, ASTContext& C) { decl->setDefinition(D.ReadBool()); decl->IntegerType = QualType::ReadVal(D); - Decl* next_declarator; - Decl* Elist; - - D.BatchReadOwnedPtrs(Elist, next_declarator, C); - - decl->setDeclChain(cast_or_null(Elist)); + Decl* next_declarator = D.ReadOwnedPtr(C); decl->setNextDeclarator(cast_or_null(next_declarator)); return decl; @@ -451,14 +462,17 @@ EnumConstantDecl* EnumConstantDecl::CreateImpl(Deserializer& D, ASTContext& C) { //===----------------------------------------------------------------------===// void FieldDecl::EmitImpl(Serializer& S) const { + S.EmitBool(Mutable); S.Emit(getType()); - NamedDecl::EmitInRec(S); + ScopedDecl::EmitInRec(S); S.EmitOwnedPtr(BitWidth); } FieldDecl* FieldDecl::CreateImpl(Deserializer& D, ASTContext& C) { void *Mem = C.getAllocator().Allocate(); - FieldDecl* decl = new (Mem) FieldDecl(SourceLocation(), NULL, QualType(), 0); + FieldDecl* decl = new (Mem) FieldDecl(Field, 0, SourceLocation(), NULL, + QualType(), 0, false, 0); + decl->Mutable = D.ReadBool(); decl->DeclType.ReadBackpatch(D); decl->ReadInRec(D, C); decl->BitWidth = D.ReadOwnedPtr(C); @@ -579,13 +593,7 @@ void RecordDecl::EmitImpl(Serializer& S) const { ScopedDecl::EmitInRec(S); S.EmitBool(isDefinition()); S.EmitBool(hasFlexibleArrayMember()); - S.EmitSInt(getNumMembers()); - if (getNumMembers() > 0) { - assert (Members); - S.BatchEmitOwnedPtrs((unsigned) getNumMembers(), (Decl**) &Members[0]); - } - else - ScopedDecl::EmitOutRec(S); + ScopedDecl::EmitOutRec(S); } RecordDecl* RecordDecl::CreateImpl(Deserializer& D, ASTContext& C) { @@ -597,17 +605,8 @@ RecordDecl* RecordDecl::CreateImpl(Deserializer& D, ASTContext& C) { decl->ScopedDecl::ReadInRec(D, C); decl->setDefinition(D.ReadBool()); decl->setHasFlexibleArrayMember(D.ReadBool()); - decl->NumMembers = D.ReadSInt(); - - if (decl->getNumMembers() > 0) { - decl->Members = new FieldDecl*[(unsigned) decl->getNumMembers()]; - - D.BatchReadOwnedPtrs((unsigned) decl->getNumMembers(), - (Decl**) &decl->Members[0], C); - } - else - decl->ScopedDecl::ReadOutRec(D, C); - + decl->ScopedDecl::ReadOutRec(D, C); + return decl; } diff --git a/lib/AST/DeclarationName.cpp b/lib/AST/DeclarationName.cpp index 649b092db0..af983feed1 100644 --- a/lib/AST/DeclarationName.cpp +++ b/lib/AST/DeclarationName.cpp @@ -311,3 +311,9 @@ DeclarationNameTable::getCXXOperatorName(OverloadedOperatorKind Op) { return DeclarationName(&CXXOperatorNames[(unsigned)Op]); } +unsigned +llvm::DenseMapInfo:: +getHashValue(clang::DeclarationName N) { + return DenseMapInfo::getHashValue(N.getAsOpaquePtr()); +} + diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp index 14db18c134..b5f966d862 100644 --- a/lib/AST/Expr.cpp +++ b/lib/AST/Expr.cpp @@ -353,7 +353,7 @@ static bool DeclCanBeLvalue(const NamedDecl *Decl, ASTContext &Ctx) { = dyn_cast(Decl)) return NTTParm->getType()->isReferenceType(); - return isa(Decl) || isa(Decl) || + return isa(Decl) || isa(Decl) || // C++ 3.10p2: An lvalue refers to an object or function. (Ctx.getLangOptions().CPlusPlus && (isa(Decl) || isa(Decl))); @@ -1222,10 +1222,15 @@ static int64_t evaluateOffsetOf(ASTContext& C, const Expr *E) const ASTRecordLayout &RL = C.getASTRecordLayout(RD); FieldDecl *FD = ME->getMemberDecl(); - // FIXME: This is linear time. - unsigned i = 0, e = 0; - for (i = 0, e = RD->getNumMembers(); i != e; i++) { - if (RD->getMember(i) == FD) + // FIXME: This is linear time. And the fact that we're indexing + // into the layout by position in the record means that we're + // either stuck numbering the fields in the AST or we have to keep + // the linear search (yuck and yuck). + unsigned i = 0; + for (RecordDecl::field_iterator Field = RD->field_begin(), + FieldEnd = RD->field_end(); + Field != FieldEnd; (void)++Field, ++i) { + if (*Field == FD) break; } diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp index 341baeab85..7a83d6c063 100644 --- a/lib/AST/ExprConstant.cpp +++ b/lib/AST/ExprConstant.cpp @@ -156,9 +156,11 @@ APValue LValueExprEvaluator::VisitMemberExpr(MemberExpr *E) { FieldDecl *FD = E->getMemberDecl(); // FIXME: This is linear time. - unsigned i = 0, e = 0; - for (i = 0, e = RD->getNumMembers(); i != e; i++) { - if (RD->getMember(i) == FD) + unsigned i = 0; + for (RecordDecl::field_iterator Field = RD->field_begin(), + FieldEnd = RD->field_end(); + Field != FieldEnd; (void)++Field, ++i) { + if (*Field == FD) break; } diff --git a/lib/Analysis/RegionStore.cpp b/lib/Analysis/RegionStore.cpp index 563a1fe9b7..f8fc88612e 100644 --- a/lib/Analysis/RegionStore.cpp +++ b/lib/Analysis/RegionStore.cpp @@ -433,8 +433,13 @@ SVal RegionStoreManager::RetrieveStruct(Store store, const TypedRegion* R) { llvm::ImmutableList StructVal = getBasicVals().getEmptySValList(); - for (int i = RD->getNumMembers() - 1; i >= 0; --i) { - FieldRegion* FR = MRMgr.getFieldRegion(RD->getMember(i), R); + for (DeclContext::reverse_decl_iterator Mem = RD->decls_rbegin(); + Mem != RD->decls_rend(); ++Mem) { + FieldDecl *FD = dyn_cast(*Mem); + if (!FD) + continue; + + FieldRegion* FR = MRMgr.getFieldRegion(FD, R); RegionBindingsTy B(static_cast(store)); RegionBindingsTy::data_type* data = B.lookup(FR); diff --git a/lib/CodeGen/CGDebugInfo.cpp b/lib/CodeGen/CGDebugInfo.cpp index d93bccd2ff..67c60aae07 100644 --- a/lib/CodeGen/CGDebugInfo.cpp +++ b/lib/CodeGen/CGDebugInfo.cpp @@ -289,10 +289,11 @@ llvm::DIType CGDebugInfo::CreateType(const EnumType *Ty, llvm::SmallVector Enumerators; // Create DIEnumerator elements for each enumerator. - for (EnumConstantDecl *Elt = Decl->getEnumConstantList(); Elt; - Elt = dyn_cast_or_null(Elt->getNextDeclarator())) { - Enumerators.push_back(DebugFactory.CreateEnumerator(Elt->getNameAsString(), - Elt->getInitVal().getZExtValue())); + for (EnumDecl::enumerator_iterator Enum = Decl->enumerator_begin(), + EnumEnd = Decl->enumerator_end(); + Enum != EnumEnd; ++Enum) { + Enumerators.push_back(DebugFactory.CreateEnumerator(Enum->getNameAsString(), + Enum->getInitVal().getZExtValue())); } // Return a CompositeType for the enum itself. diff --git a/lib/CodeGen/CGExprAgg.cpp b/lib/CodeGen/CGExprAgg.cpp index 65f8a1a2e4..834d7483ba 100644 --- a/lib/CodeGen/CGExprAgg.cpp +++ b/lib/CodeGen/CGExprAgg.cpp @@ -434,20 +434,24 @@ void AggExprEmitter::VisitInitListExpr(InitListExpr *E) { // the optimizer, especially with bitfields. unsigned NumInitElements = E->getNumInits(); RecordDecl *SD = E->getType()->getAsRecordType()->getDecl(); - unsigned NumMembers = SD->getNumMembers() - SD->hasFlexibleArrayMember(); unsigned CurInitVal = 0; bool isUnion = E->getType()->isUnionType(); // Here we iterate over the fields; this makes it simpler to both // default-initialize fields and skip over unnamed fields. - for (unsigned CurFieldNo = 0; CurFieldNo != NumMembers; ++CurFieldNo) { - FieldDecl *CurField = SD->getMember(CurFieldNo); - if (CurField->getIdentifier() == 0) { + for (RecordDecl::field_iterator Field = SD->field_begin(), + FieldEnd = SD->field_end(); + Field != FieldEnd; ++Field) { + // We're done once we hit the flexible array member + if (Field->getType()->isIncompleteArrayType()) + break; + + if (Field->getIdentifier() == 0) { // Initializers can't initialize unnamed fields, e.g. "int : 20;" continue; } // FIXME: volatility - LValue FieldLoc = CGF.EmitLValueForField(DestPtr, CurField, isUnion,0); + LValue FieldLoc = CGF.EmitLValueForField(DestPtr, *Field, isUnion,0); if (CurInitVal < NumInitElements) { // Store the initializer into the field // This will probably have to get a bit smarter when we support @@ -455,7 +459,7 @@ void AggExprEmitter::VisitInitListExpr(InitListExpr *E) { EmitInitializationToLValue(E->getInit(CurInitVal++), FieldLoc); } else { // We're out of initalizers; default-initialize to null - EmitNullInitializationToLValue(FieldLoc, CurField->getType()); + EmitNullInitializationToLValue(FieldLoc, Field->getType()); } // Unions only initialize one field. diff --git a/lib/CodeGen/CGExprConstant.cpp b/lib/CodeGen/CGExprConstant.cpp index 7f294e2996..52d99dc60e 100644 --- a/lib/CodeGen/CGExprConstant.cpp +++ b/lib/CodeGen/CGExprConstant.cpp @@ -187,16 +187,17 @@ public: unsigned EltNo = 0; // Element no in ILE int FieldNo = 0; // Field no in RecordDecl bool RewriteType = false; - while (EltNo < ILE->getNumInits() && FieldNo < RD->getNumMembers()) { - FieldDecl* curField = RD->getMember(FieldNo); + for (RecordDecl::field_iterator Field = RD->field_begin(), + FieldEnd = RD->field_end(); + EltNo < ILE->getNumInits() && Field != FieldEnd; ++Field) { FieldNo++; - if (!curField->getIdentifier()) + if (!Field->getIdentifier()) continue; - if (curField->isBitField()) { - InsertBitfieldIntoStruct(Elts, curField, ILE->getInit(EltNo)); + if (Field->isBitField()) { + InsertBitfieldIntoStruct(Elts, *Field, ILE->getInit(EltNo)); } else { - unsigned FieldNo = CGM.getTypes().getLLVMFieldNo(curField); + unsigned FieldNo = CGM.getTypes().getLLVMFieldNo(*Field); llvm::Constant *C = CGM.EmitConstantExpr(ILE->getInit(EltNo), CGF); RewriteType |= (C->getType() != Elts[FieldNo]->getType()); Elts[FieldNo] = C; @@ -223,8 +224,10 @@ public: // Find the field decl we're initializing, if any int FieldNo = 0; // Field no in RecordDecl FieldDecl* curField = 0; - while (FieldNo < RD->getNumMembers()) { - curField = RD->getMember(FieldNo); + for (RecordDecl::field_iterator Field = RD->field_begin(), + FieldEnd = RD->field_end(); + Field != FieldEnd; ++Field) { + curField = *Field; FieldNo++; if (curField->getIdentifier()) break; diff --git a/lib/CodeGen/CGObjCMac.cpp b/lib/CodeGen/CGObjCMac.cpp index 013b0f9cc3..201f53e34d 100644 --- a/lib/CodeGen/CGObjCMac.cpp +++ b/lib/CodeGen/CGObjCMac.cpp @@ -2373,12 +2373,15 @@ ObjCTypesHelper::ObjCTypesHelper(CodeGen::CodeGenModule &cgm) RecordDecl *RD = RecordDecl::Create(Ctx, TagDecl::TK_struct, 0, SourceLocation(), &Ctx.Idents.get("_objc_super")); - FieldDecl *FieldDecls[2]; - FieldDecls[0] = FieldDecl::Create(Ctx, SourceLocation(), 0, - Ctx.getObjCIdType()); - FieldDecls[1] = FieldDecl::Create(Ctx, SourceLocation(), 0, - Ctx.getObjCClassType()); - RD->defineBody(Ctx, FieldDecls, 2); + RD->addDecl(Ctx, + FieldDecl::Create(Ctx, RD, SourceLocation(), 0, + Ctx.getObjCIdType(), 0, false, 0), + true); + RD->addDecl(Ctx, + FieldDecl::Create(Ctx, RD, SourceLocation(), 0, + Ctx.getObjCClassType(), 0, false, 0), + true); + RD->completeDefinition(Ctx); SuperCTy = Ctx.getTagDeclType(RD); SuperPtrCTy = Ctx.getPointerType(SuperCTy); diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp index 82e732163b..e83d2cd293 100644 --- a/lib/CodeGen/CodeGenModule.cpp +++ b/lib/CodeGen/CodeGenModule.cpp @@ -775,21 +775,20 @@ llvm::Function *CodeGenModule::getMemSetFn() { static void appendFieldAndPadding(CodeGenModule &CGM, std::vector& Fields, - int FieldNo, llvm::Constant* Field, + FieldDecl *FieldD, FieldDecl *NextFieldD, + llvm::Constant* Field, RecordDecl* RD, const llvm::StructType *STy) { // Append the field. Fields.push_back(Field); - int StructFieldNo = - CGM.getTypes().getLLVMFieldNo(RD->getMember(FieldNo)); + int StructFieldNo = CGM.getTypes().getLLVMFieldNo(FieldD); int NextStructFieldNo; - if (FieldNo + 1 == RD->getNumMembers()) { + if (!NextFieldD) { NextStructFieldNo = STy->getNumElements(); } else { - NextStructFieldNo = - CGM.getTypes().getLLVMFieldNo(RD->getMember(FieldNo + 1)); + NextStructFieldNo = CGM.getTypes().getLLVMFieldNo(NextFieldD); } // Append padding @@ -841,29 +840,38 @@ GetAddrOfConstantCFString(const std::string &str) { cast(getTypes().ConvertType(CFTy)); std::vector Fields; - - + RecordDecl::field_iterator Field = CFRD->field_begin(); + // Class pointer. - appendFieldAndPadding(*this, Fields, 0, CFConstantStringClassRef, CFRD, STy); + FieldDecl *CurField = *Field++; + FieldDecl *NextField = *Field++; + appendFieldAndPadding(*this, Fields, CurField, NextField, + CFConstantStringClassRef, CFRD, STy); // Flags. + CurField = NextField; + NextField = *Field++; const llvm::Type *Ty = getTypes().ConvertType(getContext().UnsignedIntTy); - appendFieldAndPadding(*this, Fields, 1, llvm::ConstantInt::get(Ty, 0x07C8), - CFRD, STy); + appendFieldAndPadding(*this, Fields, CurField, NextField, + llvm::ConstantInt::get(Ty, 0x07C8), CFRD, STy); // String pointer. + CurField = NextField; + NextField = *Field++; llvm::Constant *C = llvm::ConstantArray::get(str); C = new llvm::GlobalVariable(C->getType(), true, llvm::GlobalValue::InternalLinkage, C, ".str", &getModule()); - appendFieldAndPadding(*this, Fields, 2, + appendFieldAndPadding(*this, Fields, CurField, NextField, llvm::ConstantExpr::getGetElementPtr(C, Zeros, 2), CFRD, STy); // String length. + CurField = NextField; + NextField = 0; Ty = getTypes().ConvertType(getContext().LongTy); - appendFieldAndPadding(*this, Fields, 3, llvm::ConstantInt::get(Ty, str.length()), - CFRD, STy); + appendFieldAndPadding(*this, Fields, CurField, NextField, + llvm::ConstantInt::get(Ty, str.length()), CFRD, STy); // The struct. C = llvm::ConstantStruct::get(STy, Fields); diff --git a/lib/CodeGen/CodeGenTypes.cpp b/lib/CodeGen/CodeGenTypes.cpp index 85b10399a4..8918671332 100644 --- a/lib/CodeGen/CodeGenTypes.cpp +++ b/lib/CodeGen/CodeGenTypes.cpp @@ -392,7 +392,7 @@ const llvm::Type *CodeGenTypes::ConvertTagDeclType(const TagDecl *TD) { } else if (TD->isUnion()) { // Just use the largest element of the union, breaking ties with the // highest aligned member. - if (RD->getNumMembers() != 0) { + if (RD->field_begin() != RD->field_end()) { RecordOrganizer RO(*this, *RD); RO.layoutUnionFields(Context.getASTRecordLayout(RD)); @@ -478,16 +478,17 @@ void RecordOrganizer::layoutStructFields(const ASTRecordLayout &RL) { uint64_t llvmSize = 0; // FIXME: Make this a SmallVector std::vector LLVMFields; - int NumMembers = RD.getNumMembers(); - for (int curField = 0; curField < NumMembers; curField++) { - const FieldDecl *FD = RD.getMember(curField); + unsigned curField = 0; + for (RecordDecl::field_iterator Field = RD.field_begin(), + FieldEnd = RD.field_end(); + Field != FieldEnd; ++Field) { uint64_t offset = RL.getFieldOffset(curField); - const llvm::Type *Ty = CGT.ConvertTypeRecursive(FD->getType()); + const llvm::Type *Ty = CGT.ConvertTypeRecursive(Field->getType()); uint64_t size = CGT.getTargetData().getABITypeSizeInBits(Ty); - if (FD->isBitField()) { - Expr *BitWidth = FD->getBitWidth(); + if (Field->isBitField()) { + Expr *BitWidth = Field->getBitWidth(); llvm::APSInt FieldSize(32); bool isBitField = BitWidth->isIntegerConstantExpr(FieldSize, CGT.getContext()); @@ -498,8 +499,8 @@ void RecordOrganizer::layoutStructFields(const ASTRecordLayout &RL) { // Bitfield field info is different from other field info; // it actually ignores the underlying LLVM struct because // there isn't any convenient mapping. - CGT.addFieldInfo(FD, offset / size); - CGT.addBitFieldInfo(FD, offset % size, BitFieldSize); + CGT.addFieldInfo(*Field, offset / size); + CGT.addBitFieldInfo(*Field, offset % size, BitFieldSize); } else { // Put the element into the struct. This would be simpler // if we didn't bother, but it seems a bit too strange to @@ -510,9 +511,10 @@ void RecordOrganizer::layoutStructFields(const ASTRecordLayout &RL) { } llvmSize += size; - CGT.addFieldInfo(FD, LLVMFields.size()); + CGT.addFieldInfo(*Field, LLVMFields.size()); LLVMFields.push_back(Ty); } + ++curField; } while (llvmSize < RL.getSize()) { @@ -528,21 +530,24 @@ void RecordOrganizer::layoutStructFields(const ASTRecordLayout &RL) { /// corresponding llvm struct type. This should be invoked only after /// all fields are added. void RecordOrganizer::layoutUnionFields(const ASTRecordLayout &RL) { - for (int curField = 0; curField < RD.getNumMembers(); curField++) { - const FieldDecl *FD = RD.getMember(curField); + unsigned curField = 0; + for (RecordDecl::field_iterator Field = RD.field_begin(), + FieldEnd = RD.field_end(); + Field != FieldEnd; ++Field) { // The offset should usually be zero, but bitfields could be strange uint64_t offset = RL.getFieldOffset(curField); - if (FD->isBitField()) { - Expr *BitWidth = FD->getBitWidth(); + if (Field->isBitField()) { + Expr *BitWidth = Field->getBitWidth(); uint64_t BitFieldSize = BitWidth->getIntegerConstantExprValue(CGT.getContext()).getZExtValue(); - CGT.addFieldInfo(FD, 0); - CGT.addBitFieldInfo(FD, offset, BitFieldSize); + CGT.addFieldInfo(*Field, 0); + CGT.addBitFieldInfo(*Field, offset, BitFieldSize); } else { - CGT.addFieldInfo(FD, 0); + CGT.addFieldInfo(*Field, 0); } + ++curField; } // This looks stupid, but it is correct in the sense that diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index 572ca613e0..5ae629a6c0 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -914,7 +914,7 @@ void Parser::ParseStructUnionBody(SourceLocation RecordLoc, for (unsigned i = 0, e = FieldDeclarators.size(); i != e; ++i) { FieldDeclarator &FD = FieldDeclarators[i]; // Install the declarator into the current TagDecl. - DeclTy *Field = Actions.ActOnField(CurScope, + DeclTy *Field = Actions.ActOnField(CurScope, TagDecl, DS.getSourceRange().getBegin(), FD.D, FD.BitfieldSize); FieldDecls.push_back(Field); @@ -934,8 +934,8 @@ void Parser::ParseStructUnionBody(SourceLocation RecordLoc, continue; } llvm::SmallVector Fields; - Actions.ActOnDefs(CurScope, Tok.getLocation(), Tok.getIdentifierInfo(), - Fields); + Actions.ActOnDefs(CurScope, TagDecl, Tok.getLocation(), + Tok.getIdentifierInfo(), Fields); FieldDecls.insert(FieldDecls.end(), Fields.begin(), Fields.end()); ConsumeToken(); ExpectAndConsume(tok::r_paren, diag::err_expected_rparen); diff --git a/lib/Sema/CXXFieldCollector.h b/lib/Sema/CXXFieldCollector.h index 44d482692b..69d13515fa 100644 --- a/lib/Sema/CXXFieldCollector.h +++ b/lib/Sema/CXXFieldCollector.h @@ -18,15 +18,15 @@ #include "llvm/ADT/SmallVector.h" namespace clang { - class CXXFieldDecl; + class FieldDecl; /// CXXFieldCollector - Used to keep track of CXXFieldDecls during parsing of /// C++ classes. class CXXFieldCollector { - /// Fields - Contains all CXXFieldDecls collected during parsing of a C++ + /// Fields - Contains all FieldDecls collected during parsing of a C++ /// class. When a nested class is entered, its fields are appended to the /// fields of its parent class, when it is exited its fields are removed. - llvm::SmallVector Fields; + llvm::SmallVector Fields; /// FieldCount - Each entry represents the number of fields collected during /// the parsing of a C++ class. When a nested class is entered, a new field @@ -52,7 +52,7 @@ public: void StartClass() { FieldCount.push_back(0); } /// Add - Called by Sema::ActOnCXXMemberDeclarator. - void Add(CXXFieldDecl *D) { + void Add(FieldDecl *D) { Fields.push_back(D); ++FieldCount.back(); } @@ -62,7 +62,7 @@ public: /// getCurFields - Pointer to array of fields added to the currently parsed /// class. - CXXFieldDecl **getCurFields() { return &*(Fields.end() - getCurNumFields()); } + FieldDecl **getCurFields() { return &*(Fields.end() - getCurNumFields()); } /// FinishClass - Called by Sema::ActOnFinishCXXClassDef. void FinishClass() { diff --git a/lib/Sema/IdentifierResolver.cpp b/lib/Sema/IdentifierResolver.cpp index 5fb18f6cef..4441503528 100644 --- a/lib/Sema/IdentifierResolver.cpp +++ b/lib/Sema/IdentifierResolver.cpp @@ -51,9 +51,6 @@ public: DeclContext *IdentifierResolver::LookupContext::getContext(Decl *D) { DeclContext *Ctx; - if (CXXFieldDecl *FD = dyn_cast(D)) - return FD->getParent(); - if (EnumConstantDecl *EnumD = dyn_cast(D)) { Ctx = EnumD->getDeclContext()->getParent(); } else if (ScopedDecl *SD = dyn_cast(D)) @@ -149,7 +146,7 @@ IdentifierResolver::~IdentifierResolver() { /// if 'D' is in Scope 'S', otherwise 'S' is ignored and isDeclInScope returns /// true if 'D' belongs to the given declaration context. bool IdentifierResolver::isDeclInScope(Decl *D, DeclContext *Ctx, - Scope *S) const { + ASTContext &Context, Scope *S) const { if (Ctx->isFunctionOrMethod()) { if (S->isDeclScope(D)) return true; @@ -169,7 +166,7 @@ bool IdentifierResolver::isDeclInScope(Decl *D, DeclContext *Ctx, return false; } - return LookupContext(D) == LookupContext(Ctx); + return LookupContext(D) == LookupContext(Ctx->getPrimaryContext(Context)); } /// AddDecl - Link the decl to its shadowed decl chain. diff --git a/lib/Sema/IdentifierResolver.h b/lib/Sema/IdentifierResolver.h index 9d78513395..bc9da6126d 100644 --- a/lib/Sema/IdentifierResolver.h +++ b/lib/Sema/IdentifierResolver.h @@ -208,7 +208,8 @@ public: /// isDeclInScope - If 'Ctx' is a function/method, isDeclInScope returns true /// if 'D' is in Scope 'S', otherwise 'S' is ignored and isDeclInScope returns /// true if 'D' belongs to the given declaration context. - bool isDeclInScope(Decl *D, DeclContext *Ctx, Scope *S = 0) const; + bool isDeclInScope(Decl *D, DeclContext *Ctx, ASTContext &Context, + Scope *S = 0) const; /// AddDecl - Link the decl to its shadowed decl chain. void AddDecl(NamedDecl *D); diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp index 13226c0b0e..650b8d7d7d 100644 --- a/lib/Sema/Sema.cpp +++ b/lib/Sema/Sema.cpp @@ -68,7 +68,7 @@ static inline RecordDecl *CreateStructDecl(ASTContext &C, const char *Name) { void Sema::ActOnTranslationUnitScope(SourceLocation Loc, Scope *S) { TUScope = S; - PushDeclContext(Context.getTranslationUnitDecl()); + PushDeclContext(S, Context.getTranslationUnitDecl()); if (!PP.getLangOptions().ObjC1) return; // Synthesize "typedef struct objc_selector *SEL;" diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index 4a8f83084d..97e8507e9b 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -300,10 +300,10 @@ public: IdentifierInfo *Name, SourceLocation NameLoc, AttributeList *Attr); - virtual void ActOnDefs(Scope *S, SourceLocation DeclStart, + virtual void ActOnDefs(Scope *S, DeclTy *TagD, SourceLocation DeclStart, IdentifierInfo *ClassName, llvm::SmallVectorImpl &Decls); - virtual DeclTy *ActOnField(Scope *S, SourceLocation DeclStart, + virtual DeclTy *ActOnField(Scope *S, DeclTy *TagD, SourceLocation DeclStart, Declarator &D, ExprTy *BitfieldWidth); virtual DeclTy *ActOnIvar(Scope *S, SourceLocation DeclStart, @@ -326,7 +326,7 @@ public: DeclContext *getContainingDC(DeclContext *DC); /// Set the current declaration context until it gets popped. - void PushDeclContext(DeclContext *DC); + void PushDeclContext(Scope *S, DeclContext *DC); void PopDeclContext(); /// getCurFunctionDecl - If inside of a function body, this returns a pointer @@ -351,7 +351,7 @@ public: /// if 'D' is in Scope 'S', otherwise 'S' is ignored and isDeclInScope returns /// true if 'D' belongs to the given declaration context. bool isDeclInScope(Decl *D, DeclContext *Ctx, Scope *S = 0) { - return IdResolver.isDeclInScope(D, Ctx, S); + return IdResolver.isDeclInScope(D, Ctx, Context, S); } /// Subroutines of ActOnDeclarator(). @@ -478,7 +478,8 @@ public: /// More parsing and symbol table subroutines... Decl *LookupDecl(DeclarationName Name, unsigned NSI, Scope *S, const DeclContext *LookupCtx = 0, - bool enableLazyBuiltinCreation = true); + bool enableLazyBuiltinCreation = true, + bool LookInParent = true); ObjCInterfaceDecl *getObjCInterfaceDecl(IdentifierInfo *Id); ScopedDecl *LazilyCreateBuiltin(IdentifierInfo *II, unsigned ID, Scope *S); diff --git a/lib/Sema/SemaCXXScopeSpec.cpp b/lib/Sema/SemaCXXScopeSpec.cpp index 1f92b6f6aa..d01552c373 100644 --- a/lib/Sema/SemaCXXScopeSpec.cpp +++ b/lib/Sema/SemaCXXScopeSpec.cpp @@ -20,7 +20,25 @@ using namespace clang; namespace { Decl *LookupNestedName(DeclContext *LookupCtx, bool LookInParentCtx, - DeclarationName Name, bool &IdIsUndeclared) { + DeclarationName Name, bool &IdIsUndeclared, + ASTContext &Context) { + if (LookupCtx && !LookInParentCtx) { + IdIsUndeclared = true; + for (DeclContext::lookup_const_result I = LookupCtx->lookup(Context, Name); + I.first != I.second; ++I.first) { + IdIsUndeclared = false; + if (((*I.first)->getIdentifierNamespace() & Decl::IDNS_Tag) && + !isa(*I.first)) + return *I.first; + } + + return 0; + } + + // FIXME: Decouple this from the IdentifierResolver so that we can + // deal with lookups into the semantic parent contexts that aren't + // lexical parent contexts. + IdentifierResolver::iterator I = IdentifierResolver::begin(Name, LookupCtx, LookInParentCtx), E = IdentifierResolver::end(); @@ -73,10 +91,11 @@ Sema::CXXScopeTy *Sema::ActOnCXXNestedNameSpecifier(Scope *S, bool IdIsUndeclared; if (DC) - SD = LookupNestedName(DC, false/*LookInParentCtx*/, &II, IdIsUndeclared); + SD = LookupNestedName(DC, false/*LookInParentCtx*/, &II, IdIsUndeclared, + Context); else SD = LookupNestedName(CurContext, true/*LookInParent*/, &II, - IdIsUndeclared); + IdIsUndeclared, Context); if (SD) { if (TypedefDecl *TD = dyn_cast(SD)) { diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 41587c5aee..b541f59a22 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -74,14 +74,16 @@ DeclContext *Sema::getContainingDC(DeclContext *DC) { return DC->getLexicalParent(); } -void Sema::PushDeclContext(DeclContext *DC) { +void Sema::PushDeclContext(Scope *S, DeclContext *DC) { assert(getContainingDC(DC) == CurContext && "The next DeclContext should be lexically contained in the current one."); CurContext = DC; + S->setEntity(DC); } void Sema::PopDeclContext() { assert(CurContext && "DeclContext imbalance!"); + CurContext = getContainingDC(CurContext); } @@ -97,53 +99,90 @@ void Sema::PushOnScopeChains(NamedDecl *D, Scope *S) { // in this case the class name or enumeration name is hidden. if (TagDecl *TD = dyn_cast(D)) { // We are pushing the name of a tag (enum or class). - IdentifierResolver::iterator - I = IdResolver.begin(TD->getIdentifier(), - TD->getDeclContext(), false/*LookInParentCtx*/); - if (I != IdResolver.end() && isDeclInScope(*I, TD->getDeclContext(), S)) { - // There is already a declaration with the same name in the same - // scope. It must be found before we find the new declaration, - // so swap the order on the shadowed declaration chain. - - IdResolver.AddShadowedDecl(TD, *I); - return; + if (CurContext == TD->getDeclContext()) { + // We're pushing the tag into the current context, which might + // require some reshuffling in the identifier resolver. + IdentifierResolver::iterator + I = IdResolver.begin(TD->getIdentifier(), CurContext, + false/*LookInParentCtx*/); + if (I != IdResolver.end()) { + // There is already a declaration with the same name in the same + // scope. It must be found before we find the new declaration, + // so swap the order on the shadowed declaration chain. + IdResolver.AddShadowedDecl(TD, *I); + + // Add this declaration to the current context. + CurContext->addDecl(Context, TD); + + return; + } } } else if (getLangOptions().CPlusPlus && isa(D)) { - FunctionDecl *FD = cast(D); // We are pushing the name of a function, which might be an // overloaded name. - IdentifierResolver::iterator - I = IdResolver.begin(FD->getDeclName(), - FD->getDeclContext(), false/*LookInParentCtx*/); - if (I != IdResolver.end() && - IdResolver.isDeclInScope(*I, FD->getDeclContext(), S) && - (isa(*I) || isa(*I))) { - // There is already a declaration with the same name in the same - // scope. It must be a function or an overloaded function. - OverloadedFunctionDecl* Ovl = dyn_cast(*I); + FunctionDecl *FD = cast(D); + Decl *Prev = LookupDecl(FD->getDeclName(), Decl::IDNS_Ordinary, S, + FD->getDeclContext(), false, false); + if (Prev && (isa(Prev) || isa(Prev))) { + // There is already a declaration with the same name in + // the same scope. It must be a function or an overloaded + // function. + OverloadedFunctionDecl* Ovl = dyn_cast(Prev); if (!Ovl) { // We haven't yet overloaded this function. Take the existing // FunctionDecl and put it into an OverloadedFunctionDecl. Ovl = OverloadedFunctionDecl::Create(Context, FD->getDeclContext(), FD->getDeclName()); - Ovl->addOverload(dyn_cast(*I)); + Ovl->addOverload(dyn_cast(Prev)); - // Remove the name binding to the existing FunctionDecl... - IdResolver.RemoveDecl(*I); - - // ... and put the OverloadedFunctionDecl in its place. + // If there is an name binding for the existing FunctionDecl, + // remove it. + for (IdentifierResolver::iterator I + = IdResolver.begin(FD->getDeclName(), FD->getDeclContext(), + false/*LookInParentCtx*/); + I != IdResolver.end(); ++I) { + if (*I == Prev) { + IdResolver.RemoveDecl(*I); + S->RemoveDecl(*I); + break; + } + } + + // Add the name binding for the OverloadedFunctionDecl. IdResolver.AddDecl(Ovl); + + // Update the context with the newly-created overloaded + // function set. + FD->getDeclContext()->insert(Context, Ovl); + + S->AddDecl(Ovl); } + // We added this function declaration to the scope earlier, but + // we don't want it there because it is part of the overloaded + // function declaration. + S->RemoveDecl(FD); + // We have an OverloadedFunctionDecl. Add the new FunctionDecl // to its list of overloads. Ovl->addOverload(FD); - return; + // Add this new function declaration to the declaration context. + CurContext->addDecl(Context, FD, false); + + return; } } + if (ScopedDecl *SD = dyn_cast(D)) + CurContext->addDecl(Context, SD); + else { + // Other kinds of declarations don't currently have a context + // where they need to be inserted. + } + + IdResolver.AddDecl(D); } @@ -157,25 +196,13 @@ void Sema::ActOnPopScope(SourceLocation Loc, Scope *S) { Decl *TmpD = static_cast(*I); assert(TmpD && "This decl didn't get pushed??"); - if (isa(TmpD)) continue; + assert(isa(TmpD) && "Decl isn't NamedDecl?"); + NamedDecl *D = cast(TmpD); - assert(isa(TmpD) && "Decl isn't ScopedDecl?"); - ScopedDecl *D = cast(TmpD); - - IdentifierInfo *II = D->getIdentifier(); - if (!II) continue; - - // We only want to remove the decls from the identifier decl chains for - // local scopes, when inside a function/method. - // However, we *always* remove template parameters, since they are - // purely lexically scoped (and can never be found by qualified - // name lookup). - if (S->getFnParent() != 0 || isa(D)) - IdResolver.RemoveDecl(D); - - // Chain this decl to the containing DeclContext. - D->setNext(CurContext->getDeclChain()); - CurContext->setDeclChain(D); + if (!D->getDeclName()) continue; + + // Remove this name from our lexical scope. + IdResolver.RemoveDecl(D); } } @@ -193,21 +220,76 @@ ObjCInterfaceDecl *Sema::getObjCInterfaceDecl(IdentifierInfo *Id) { /// namespace. Decl *Sema::LookupDecl(DeclarationName Name, unsigned NSI, Scope *S, const DeclContext *LookupCtx, - bool enableLazyBuiltinCreation) { + bool enableLazyBuiltinCreation, + bool LookInParent) { if (!Name) return 0; unsigned NS = NSI; if (getLangOptions().CPlusPlus && (NS & Decl::IDNS_Ordinary)) NS |= Decl::IDNS_Tag; - IdentifierResolver::iterator - I = LookupCtx ? IdResolver.begin(Name, LookupCtx, false/*LookInParentCtx*/) - : IdResolver.begin(Name, CurContext, true/*LookInParentCtx*/); - // Scan up the scope chain looking for a decl that matches this identifier - // that is in the appropriate namespace. This search should not take long, as - // shadowing of names is uncommon, and deep shadowing is extremely uncommon. - for (; I != IdResolver.end(); ++I) - if ((*I)->getIdentifierNamespace() & NS) - return *I; + if (LookupCtx) { + assert(getLangOptions().CPlusPlus && "No qualified name lookup in C"); + + // Perform qualified name lookup into the LookupCtx. + // FIXME: Will need to look into base classes and such. + for (DeclContext::lookup_const_result I = LookupCtx->lookup(Context, Name); + I.first != I.second; ++I.first) + if ((*I.first)->getIdentifierNamespace() & NS) + return *I.first; + } else if (getLangOptions().CPlusPlus && + (NS & (Decl::IDNS_Ordinary | Decl::IDNS_Tag))) { + // Name lookup for ordinary names and tag names in C++ requires + // looking into scopes that aren't strictly lexical, and + // therefore we walk through the context as well as walking + // through the scopes. + IdentifierResolver::iterator + I = IdResolver.begin(Name, CurContext, true/*LookInParentCtx*/), + IEnd = IdResolver.end(); + for (; S; S = S->getParent()) { + // Check whether the IdResolver has anything in this scope. + // FIXME: The isDeclScope check could be expensive. Can we do better? + for (; I != IEnd && S->isDeclScope(*I); ++I) + if ((*I)->getIdentifierNamespace() & NS) + return *I; + + // If there is an entity associated with this scope, it's a + // DeclContext. We might need to perform qualified lookup into + // it. + DeclContext *Ctx = static_cast(S->getEntity()); + while (Ctx && Ctx->isFunctionOrMethod()) + Ctx = Ctx->getParent(); + while (Ctx && (Ctx->isNamespace() || Ctx->isCXXRecord())) { + // Look for declarations of this name in this scope. + for (DeclContext::lookup_const_result I = Ctx->lookup(Context, Name); + I.first != I.second; ++I.first) { + // FIXME: Cache this result in the IdResolver + if ((*I.first)->getIdentifierNamespace() & NS) + return *I.first; + } + + Ctx = Ctx->getParent(); + } + + if (!LookInParent) + return 0; + } + } else { + // Unqualified name lookup for names in our lexical scope. This + // name lookup suffices when all of the potential names are known + // to have been pushed onto the IdResolver, as happens in C + // (always) and in C++ for names in the "label" namespace. + assert(!LookupCtx && "Can't perform qualified name lookup here"); + IdentifierResolver::iterator I + = IdResolver.begin(Name, CurContext, LookInParent); + + // Scan up the scope chain looking for a decl that matches this + // identifier that is in the appropriate namespace. This search + // should not take long, as shadowing of names is uncommon, and + // deep shadowing is extremely uncommon. + for (; I != IdResolver.end(); ++I) + if ((*I)->getIdentifierNamespace() & NS) + return *I; + } // If we didn't find a use of this identifier, and if the identifier // corresponds to a compiler builtin, create the decl object for the builtin @@ -826,7 +908,8 @@ Sema::ActOnDeclarator(Scope *S, Declarator &D, DeclTy *lastDecl) { // The scope passed in may not be a decl scope. Zip up the scope tree until // we find one that is. - while ((S->getFlags() & Scope::DeclScope) == 0) + while ((S->getFlags() & Scope::DeclScope) == 0 || + (S->getFlags() & Scope::TemplateParamScope) != 0) S = S->getParent(); DeclContext *DC; @@ -854,6 +937,7 @@ Sema::ActOnDeclarator(Scope *S, Declarator &D, DeclTy *lastDecl) { // No previous declaration in the qualifying scope. Diag(D.getIdentifierLoc(), diag::err_typecheck_no_member) << Name << D.getCXXScopeSpec().getRange(); + InvalidDecl = true; } else if (!CurContext->Encloses(DC)) { // The qualifying scope doesn't enclose the original declaration. // Emit diagnostic based on current scope. @@ -865,6 +949,7 @@ Sema::ActOnDeclarator(Scope *S, Declarator &D, DeclTy *lastDecl) { Diag(L, diag::err_invalid_declarator_scope) << Name << cast(DC)->getDeclName() << R; } + InvalidDecl = true; } } @@ -1127,23 +1212,42 @@ Sema::ActOnDeclarator(Scope *S, Declarator &D, DeclTy *lastDecl) { if (OldDecl == PrevDecl) { // Remove the name binding for the previous - // declaration. We'll add the binding back later, but then - // it will refer to the new declaration (which will - // contain more information). - IdResolver.RemoveDecl(cast(PrevDecl)); + // declaration. + if (S->isDeclScope(PrevDecl)) { + IdResolver.RemoveDecl(cast(PrevDecl)); + S->RemoveDecl(PrevDecl); + } + + // Introduce the new binding for this declaration. + IdResolver.AddDecl(NewFD); + if (getLangOptions().CPlusPlus && NewFD->getParent()) + NewFD->getParent()->insert(Context, NewFD); + + // Add the redeclaration to the current scope, since we'll + // be skipping PushOnScopeChains. + S->AddDecl(NewFD); } else { // We need to update the OverloadedFunctionDecl with the // latest declaration of this function, so that name // lookup will always refer to the latest declaration of // this function. *MatchedDecl = NewFD; + } - // Add the redeclaration to the current scope, since we'll - // be skipping PushOnScopeChains. - S->AddDecl(NewFD); + if (getLangOptions().CPlusPlus) { + // Add this declaration to the current context. + CurContext->addDecl(Context, NewFD, false); - return NewFD; + // Check default arguments now that we have merged decls. + CheckCXXDefaultArguments(NewFD); } + + // Set the lexical context. If the declarator has a C++ + // scope specifier, the lexical context will be different + // from the semantic context. + NewFD->setLexicalDeclContext(CurContext); + + return NewFD; } } } @@ -2071,7 +2175,7 @@ Sema::ActOnParamDeclarator(Scope *S, Declarator &D) { parmDeclType = Context.getArrayDecayedType(parmDeclType); } else if (parmDeclType->isFunctionType()) parmDeclType = Context.getPointerType(parmDeclType); - + ParmVarDecl *New = ParmVarDecl::Create(Context, CurContext, D.getIdentifierLoc(), II, parmDeclType, StorageClass, @@ -2079,9 +2183,11 @@ Sema::ActOnParamDeclarator(Scope *S, Declarator &D) { if (D.getInvalidType()) New->setInvalidDecl(); - + + // Add the parameter declaration into this scope. + S->AddDecl(New); if (II) - PushOnScopeChains(New, S); + IdResolver.AddDecl(New); ProcessDeclAttributes(New, D); return New; @@ -2133,7 +2239,7 @@ Sema::DeclTy *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, DeclTy *D) { Diag(Definition->getLocation(), diag::note_previous_definition); } - PushDeclContext(FD); + PushDeclContext(FnBodyScope, FD); // Check the validity of our function parameters CheckParmsForFunctionDef(FD); @@ -2573,17 +2679,19 @@ Sema::DeclTy *Sema::ActOnTagStruct(Scope *S, TagDecl::TagKind Kind, TagKind TK, /// Collect the instance variables declared in an Objective-C object. Used in /// the creation of structures from objects using the @defs directive. -static void CollectIvars(ObjCInterfaceDecl *Class, ASTContext& Ctx, +static void CollectIvars(ObjCInterfaceDecl *Class, RecordDecl *Record, + ASTContext& Ctx, llvm::SmallVectorImpl &ivars) { if (Class->getSuperClass()) - CollectIvars(Class->getSuperClass(), Ctx, ivars); + CollectIvars(Class->getSuperClass(), Record, Ctx, ivars); // For each ivar, create a fresh ObjCAtDefsFieldDecl. for (ObjCInterfaceDecl::ivar_iterator I=Class->ivar_begin(), E=Class->ivar_end(); I!=E; ++I) { ObjCIvarDecl* ID = *I; - ivars.push_back(ObjCAtDefsFieldDecl::Create(Ctx, ID->getLocation(), + ivars.push_back(ObjCAtDefsFieldDecl::Create(Ctx, Record, + ID->getLocation(), ID->getIdentifier(), ID->getType(), ID->getBitWidth())); @@ -2592,7 +2700,7 @@ static void CollectIvars(ObjCInterfaceDecl *Class, ASTContext& Ctx, /// Called whenever @defs(ClassName) is encountered in the source. Inserts the /// instance variables of ClassName into Decls. -void Sema::ActOnDefs(Scope *S, SourceLocation DeclStart, +void Sema::ActOnDefs(Scope *S, DeclTy *TagD, SourceLocation DeclStart, IdentifierInfo *ClassName, llvm::SmallVectorImpl &Decls) { // Check that ClassName is a valid class @@ -2602,7 +2710,17 @@ void Sema::ActOnDefs(Scope *S, SourceLocation DeclStart, return; } // Collect the instance variables - CollectIvars(Class, Context, Decls); + CollectIvars(Class, dyn_cast((Decl*)TagD), Context, Decls); + + // Introduce all of these fields into the appropriate scope. + for (llvm::SmallVectorImpl::iterator D = Decls.begin(); + D != Decls.end(); ++D) { + FieldDecl *FD = cast((Decl*)*D); + if (getLangOptions().CPlusPlus) + PushOnScopeChains(cast(FD), S); + else if (RecordDecl *Record = dyn_cast((Decl*)TagD)) + Record->addDecl(Context, FD); + } } /// TryToFixInvalidVariablyModifiedType - Helper method to turn variable array @@ -2657,12 +2775,13 @@ bool Sema::VerifyBitField(SourceLocation FieldLoc, IdentifierInfo *FieldName, /// ActOnField - Each field of a struct/union/class is passed into this in order /// to create a FieldDecl object for it. -Sema::DeclTy *Sema::ActOnField(Scope *S, +Sema::DeclTy *Sema::ActOnField(Scope *S, DeclTy *TagD, SourceLocation DeclStart, Declarator &D, ExprTy *BitfieldWidth) { IdentifierInfo *II = D.getIdentifier(); Expr *BitWidth = (Expr*)BitfieldWidth; SourceLocation Loc = DeclStart; + RecordDecl *Record = (RecordDecl *)TagD; if (II) Loc = D.getIdentifierLoc(); // FIXME: Unnamed fields can be handled in various different ways, for @@ -2699,22 +2818,24 @@ Sema::DeclTy *Sema::ActOnField(Scope *S, // FIXME: Chain fielddecls together. FieldDecl *NewFD; - if (getLangOptions().CPlusPlus) { - // FIXME: Replace CXXFieldDecls with FieldDecls for simple structs. - NewFD = CXXFieldDecl::Create(Context, cast(CurContext), - Loc, II, T, - D.getDeclSpec().getStorageClassSpec() == - DeclSpec::SCS_mutable, BitWidth); - if (II) - PushOnScopeChains(NewFD, S); - } - else - NewFD = FieldDecl::Create(Context, Loc, II, T, BitWidth); - + // FIXME: We don't want CurContext for C, do we? No, we'll need some + // other way to determine the current RecordDecl. + NewFD = FieldDecl::Create(Context, Record, + Loc, II, T, BitWidth, + D.getDeclSpec().getStorageClassSpec() == + DeclSpec::SCS_mutable, + /*PrevDecl=*/0); + ProcessDeclAttributes(NewFD, D); if (D.getInvalidType() || InvalidDecl) NewFD->setInvalidDecl(); + + if (II && getLangOptions().CPlusPlus) + PushOnScopeChains(NewFD, S); + else + Record->addDecl(Context, NewFD); + return NewFD; } @@ -2921,7 +3042,7 @@ void Sema::ActOnFields(Scope* S, // Okay, we successfully defined 'Record'. if (Record) { - Record->defineBody(Context, &RecFields[0], RecFields.size()); + Record->completeDefinition(Context); // If this is a C++ record, HandleTagDeclDefinition will be invoked in // Sema::ActOnFinishCXXClassDef. if (!isa(Record)) @@ -3189,7 +3310,7 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, DeclTy *EnumDeclX, ECD->setType(NewTy); } - Enum->defineElements(EltList, BestType); + Enum->completeDefinition(Context, BestType); Consumer.HandleTagDeclDefinition(Enum); } diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp index bff650db5f..5c2b49472b 100644 --- a/lib/Sema/SemaDeclAttr.cpp +++ b/lib/Sema/SemaDeclAttr.cpp @@ -904,8 +904,10 @@ static void HandleTransparentUnionAttr(Decl *d, const AttributeList &Attr, // FIXME: This isn't supposed to be restricted to pointers, but otherwise // we might silently generate incorrect code; see following code - for (int i = 0; i < RD->getNumMembers(); i++) { - if (!RD->getMember(i)->getType()->isPointerType()) { + for (RecordDecl::field_iterator Field = RD->field_begin(), + FieldEnd = RD->field_end(); + Field != FieldEnd; ++Field) { + if (!Field->getType()->isPointerType()) { S.Diag(Attr.getLoc(), diag::warn_transparent_union_nonpointer); return; } diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index bedf3f7d6b..31ecfbabd2 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -382,7 +382,7 @@ void Sema::ActOnBaseSpecifiers(DeclTy *ClassDecl, BaseTy **Bases, /// definition, when on C++. void Sema::ActOnStartCXXClassDef(Scope *S, DeclTy *D, SourceLocation LBrace) { CXXRecordDecl *Dcl = cast(static_cast(D)); - PushDeclContext(Dcl); + PushDeclContext(S, Dcl); FieldCollector->StartClass(); if (Dcl->getIdentifier()) { @@ -486,7 +486,8 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D, bool InvalidDecl = false; if (isInstField) - Member = static_cast(ActOnField(S, Loc, D, BitWidth)); + Member = static_cast(ActOnField(S, cast(CurContext), + Loc, D, BitWidth)); else Member = static_cast(ActOnDeclarator(S, D, LastInGroup)); @@ -593,7 +594,7 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D, Member->setInvalidDecl(); if (isInstField) { - FieldCollector->Add(cast(Member)); + FieldCollector->Add(cast(Member)); return LastInGroup; } return Member; @@ -632,7 +633,10 @@ Sema::ActOnMemInitializer(DeclTy *ConstructorD, // mem-initializer-id for the hidden base class may be specified // using a qualified name. ] // Look for a member, first. - CXXFieldDecl *Member = ClassDecl->getMember(MemberOrBase); + FieldDecl *Member = 0; + DeclContext::lookup_result Result = ClassDecl->lookup(Context, MemberOrBase); + if (Result.first != Result.second) + Member = dyn_cast(*Result.first); // FIXME: Handle members of an anonymous union. @@ -1251,43 +1255,42 @@ Sema::DeclTy *Sema::ActOnStartNamespaceDef(Scope *NamespcScope, // in that declarative region, it is treated as an original-namespace-name. Decl *PrevDecl = - LookupDecl(II, Decl::IDNS_Tag | Decl::IDNS_Ordinary, DeclRegionScope, 0, - /*enableLazyBuiltinCreation=*/false); - - if (PrevDecl && isDeclInScope(PrevDecl, CurContext, DeclRegionScope)) { - if (NamespaceDecl *OrigNS = dyn_cast(PrevDecl)) { - // This is an extended namespace definition. - // Attach this namespace decl to the chain of extended namespace - // definitions. - NamespaceDecl *NextNS = OrigNS; - while (NextNS->getNextNamespace()) - NextNS = NextNS->getNextNamespace(); - - NextNS->setNextNamespace(Namespc); - Namespc->setOriginalNamespace(OrigNS); - - // We won't add this decl to the current scope. We want the namespace - // name to return the original namespace decl during a name lookup. - } else { - // This is an invalid name redefinition. - Diag(Namespc->getLocation(), diag::err_redefinition_different_kind) - << Namespc->getDeclName(); - Diag(PrevDecl->getLocation(), diag::note_previous_definition); - Namespc->setInvalidDecl(); - // Continue on to push Namespc as current DeclContext and return it. + LookupDecl(II, Decl::IDNS_Tag | Decl::IDNS_Ordinary, DeclRegionScope, 0, + /*enableLazyBuiltinCreation=*/false, + /*LookupInParent=*/false); + + if (NamespaceDecl *OrigNS = dyn_cast_or_null(PrevDecl)) { + // This is an extended namespace definition. + // Attach this namespace decl to the chain of extended namespace + // definitions. + OrigNS->setNextNamespace(Namespc); + Namespc->setOriginalNamespace(OrigNS->getOriginalNamespace()); + + // Remove the previous declaration from the scope. + if (DeclRegionScope->isDeclScope(OrigNS)) { + IdResolver.RemoveDecl(OrigNS); + DeclRegionScope->RemoveDecl(OrigNS); } - } else { - // This namespace name is declared for the first time. - PushOnScopeChains(Namespc, DeclRegionScope); - } - } - else { + } else if (PrevDecl) { + // This is an invalid name redefinition. + Diag(Namespc->getLocation(), diag::err_redefinition_different_kind) + << Namespc->getDeclName(); + Diag(PrevDecl->getLocation(), diag::note_previous_definition); + Namespc->setInvalidDecl(); + // Continue on to push Namespc as current DeclContext and return it. + } + + PushOnScopeChains(Namespc, DeclRegionScope); + } else { // FIXME: Handle anonymous namespaces } // Although we could have an invalid decl (i.e. the namespace name is a // redefinition), push it as current DeclContext and try to continue parsing. - PushDeclContext(Namespc->getOriginalNamespace()); + // FIXME: We should be able to push Namespc here, so that the + // each DeclContext for the namespace has the declarations + // that showed up in that particular namespace definition. + PushDeclContext(NamespcScope, Namespc); return Namespc; } diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp index fa73bcf259..d135724770 100644 --- a/lib/Sema/SemaDeclObjC.cpp +++ b/lib/Sema/SemaDeclObjC.cpp @@ -36,7 +36,7 @@ void Sema::ObjCActOnStartOfMethodDef(Scope *FnBodyScope, DeclTy *D) { AddFactoryMethodToGlobalPool(MDecl); // Allow all of Sema to see that we are entering a method definition. - PushDeclContext(MDecl); + PushDeclContext(FnBodyScope, MDecl); // Create Decl objects for each parameter, entrring them in the scope for // binding to their use. diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index b254254241..ba5d28a633 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -453,13 +453,13 @@ Sema::ExprResult Sema::ActOnDeclarationNameExpr(Scope *S, SourceLocation Loc, } } - if (CXXFieldDecl *FD = dyn_cast(D)) { + if (FieldDecl *FD = dyn_cast(D)) { if (CXXMethodDecl *MD = dyn_cast(CurContext)) { if (MD->isStatic()) // "invalid use of member 'x' in static member function" return Diag(Loc, diag::err_invalid_member_use_in_static_method) << FD->getDeclName(); - if (cast(MD->getParent()) != FD->getParent()) + if (MD->getParent() != FD->getDeclContext()) // "invalid use of nonstatic data member 'x'" return Diag(Loc, diag::err_invalid_non_static_member_use) << FD->getDeclName(); @@ -1231,20 +1231,28 @@ ActOnMemberReferenceExpr(ExprTy *Base, SourceLocation OpLoc, return Diag(OpLoc, diag::err_typecheck_incomplete_tag) << RDecl->getDeclName() << BaseExpr->getSourceRange(); // The record definition is complete, now make sure the member is valid. - FieldDecl *MemberDecl = RDecl->getMember(&Member); - if (!MemberDecl) + // FIXME: Qualified name lookup for C++ is a bit more complicated + // than this. + DeclContext::lookup_result Lookup = RDecl->lookup(Context, &Member); + if (Lookup.first == Lookup.second) { return Diag(MemberLoc, diag::err_typecheck_no_member) << &Member << BaseExpr->getSourceRange(); + } + + FieldDecl *MemberDecl = dyn_cast(*Lookup.first); + if (!MemberDecl) { + unsigned DiagID = PP.getDiagnostics().getCustomDiagID(Diagnostic::Error, + "Clang only supports references to members"); + return Diag(MemberLoc, DiagID); + } // Figure out the type of the member; see C99 6.5.2.3p3 // FIXME: Handle address space modifiers QualType MemberType = MemberDecl->getType(); unsigned combinedQualifiers = MemberType.getCVRQualifiers() | BaseType.getCVRQualifiers(); - if (CXXFieldDecl *CXXMember = dyn_cast(MemberDecl)) { - if (CXXMember->isMutable()) - combinedQualifiers &= ~QualType::Const; - } + if (MemberDecl->isMutable()) + combinedQualifiers &= ~QualType::Const; MemberType = MemberType.getQualifiedType(combinedQualifiers); return new MemberExpr(BaseExpr, OpKind == tok::arrow, MemberDecl, @@ -3484,7 +3492,11 @@ Sema::ExprResult Sema::ActOnBuiltinOffsetOf(SourceLocation BuiltinLoc, // Get the decl corresponding to this. RecordDecl *RD = RC->getDecl(); - FieldDecl *MemberDecl = RD->getMember(OC.U.IdentInfo); + FieldDecl *MemberDecl = 0; + DeclContext::lookup_result Lookup = RD->lookup(Context, OC.U.IdentInfo); + if (Lookup.first != Lookup.second) + MemberDecl = dyn_cast(*Lookup.first); + if (!MemberDecl) return Diag(BuiltinLoc, diag::err_typecheck_no_member) << OC.U.IdentInfo << SourceRange(OC.LocStart, OC.LocEnd); @@ -3552,7 +3564,7 @@ void Sema::ActOnBlockStart(SourceLocation CaretLoc, Scope *BlockScope) { BSI->TheScope = BlockScope; BSI->TheDecl = BlockDecl::Create(Context, CurContext, CaretLoc); - PushDeclContext(BSI->TheDecl); + PushDeclContext(BlockScope, BSI->TheDecl); } void Sema::ActOnBlockArguments(Declarator &ParamInfo) { diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index 27b0ba34d1..a32a6f68fa 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -412,9 +412,8 @@ bool Sema::FindAllocationOverload(SourceLocation StartLoc, DeclarationName Name, DeclContext *Ctx, bool AllowMissing, FunctionDecl *&Operator) { - IdentifierResolver::iterator I = - IdResolver.begin(Name, Ctx, /*LookInParentCtx=*/false); - if (I == IdResolver.end()) { + DeclContext::lookup_result Lookup = Ctx->lookup(Context, Name); + if (Lookup.first == Lookup.second) { if (AllowMissing) return false; // FIXME: Bad location information. @@ -423,7 +422,7 @@ bool Sema::FindAllocationOverload(SourceLocation StartLoc, DeclarationName Name, } OverloadCandidateSet Candidates; - NamedDecl *Decl = *I; + NamedDecl *Decl = *Lookup.first; // Even member operator new/delete are implicitly treated as static, so don't // use AddMemberCandidate. if (FunctionDecl *Fn = dyn_cast_or_null(Decl)) diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp index 42f9b14085..f36d3a504f 100644 --- a/lib/Sema/SemaInit.cpp +++ b/lib/Sema/SemaInit.cpp @@ -15,6 +15,8 @@ #include "clang/AST/ASTContext.h" #include "clang/AST/Expr.h" #include "clang/Basic/Diagnostic.h" +#include // for std::count_if +#include // for std::mem_fun namespace clang { @@ -39,10 +41,9 @@ int InitListChecker::numArrayElements(QualType DeclType) { int InitListChecker::numStructUnionElements(QualType DeclType) { RecordDecl *structDecl = DeclType->getAsRecordType()->getDecl(); - int InitializableMembers = 0; - for (int i = 0; i < structDecl->getNumMembers(); i++) - if (structDecl->getMember(i)->getIdentifier()) - ++InitializableMembers; + int InitializableMembers + = std::count_if(structDecl->field_begin(), structDecl->field_end(), + std::mem_fun(&FieldDecl::getDeclName)); if (structDecl->isUnion()) return std::min(InitializableMembers, 1); return InitializableMembers - structDecl->hasFlexibleArrayMember(); @@ -286,21 +287,28 @@ void InitListChecker::CheckStructUnionTypes(InitListExpr *IList, // If structDecl is a forward declaration, this loop won't do anything; // That's okay, because an error should get printed out elsewhere. It // might be worthwhile to skip over the rest of the initializer, though. - int numMembers = DeclType->getAsRecordType()->getDecl()->getNumMembers() - - structDecl->hasFlexibleArrayMember(); - for (int i = 0; i < numMembers; i++) { + RecordDecl *RD = DeclType->getAsRecordType()->getDecl(); + for (RecordDecl::field_iterator Field = RD->field_begin(), + FieldEnd = RD->field_end(); + Field != FieldEnd; ++Field) { + // If we've hit the flexible array member at the end, we're done. + if (Field->getType()->isIncompleteArrayType()) + break; + // Don't attempt to go past the end of the init list if (Index >= IList->getNumInits()) break; - FieldDecl * curField = structDecl->getMember(i); - if (!curField->getIdentifier()) { + + if (!Field->getIdentifier()) { // Don't initialize unnamed fields, e.g. "int : 20;" continue; } - CheckSubElementType(IList, curField->getType(), Index); + + CheckSubElementType(IList, Field->getType(), Index); if (DeclType->isUnionType()) break; } + // FIXME: Implement flexible array initialization GCC extension (it's a // really messy extension to implement, unfortunately...the necessary // information isn't actually even here!) diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index 8a68d5be5c..307abe3ac9 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -1955,10 +1955,9 @@ void Sema::AddOperatorCandidates(OverloadedOperatorKind Op, Scope *S, // (13.3.1.1.1); otherwise, the set of member candidates is // empty. if (const RecordType *T1Rec = T1->getAsRecordType()) { - IdentifierResolver::iterator I - = IdResolver.begin(OpName, cast(T1Rec)->getDecl(), - /*LookInParentCtx=*/false); - NamedDecl *MemberOps = (I == IdResolver.end())? 0 : *I; + DeclContext::lookup_const_result Lookup + = cast(T1Rec)->getDecl()->lookup(Context, OpName); + NamedDecl *MemberOps = (Lookup.first == Lookup.second)? 0 : *Lookup.first; if (CXXMethodDecl *Method = dyn_cast_or_null(MemberOps)) AddMethodCandidate(Method, Args[0], Args+1, NumArgs - 1, CandidateSet, /*SuppressUserConversions=*/false); @@ -3118,11 +3117,10 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object, // ordinary lookup of the name operator() in the context of // (E).operator(). OverloadCandidateSet CandidateSet; - IdentifierResolver::iterator I - = IdResolver.begin(Context.DeclarationNames.getCXXOperatorName(OO_Call), - cast(Record)->getDecl(), - /*LookInParentCtx=*/false); - NamedDecl *MemberOps = (I == IdResolver.end())? 0 : *I; + DeclarationName OpName = Context.DeclarationNames.getCXXOperatorName(OO_Call); + DeclContext::lookup_const_result Lookup + = cast(Record)->getDecl()->lookup(Context, OpName); + NamedDecl *MemberOps = (Lookup.first == Lookup.second)? 0 : *Lookup.first; if (CXXMethodDecl *Method = dyn_cast_or_null(MemberOps)) AddMethodCandidate(Method, Object, Args, NumArgs, CandidateSet, /*SuppressUserConversions=*/false); @@ -3315,10 +3313,9 @@ Sema::BuildOverloadedArrowExpr(Expr *Base, SourceLocation OpLoc, DeclarationName OpName = Context.DeclarationNames.getCXXOperatorName(OO_Arrow); OverloadCandidateSet CandidateSet; const RecordType *BaseRecord = Base->getType()->getAsRecordType(); - IdentifierResolver::iterator I - = IdResolver.begin(OpName, cast(BaseRecord)->getDecl(), - /*LookInParentCtx=*/false); - NamedDecl *MemberOps = (I == IdResolver.end())? 0 : *I; + DeclContext::lookup_const_result Lookup + = cast(BaseRecord)->getDecl()->lookup(Context, OpName); + NamedDecl *MemberOps = (Lookup.first == Lookup.second)? 0 : *Lookup.first; if (CXXMethodDecl *Method = dyn_cast_or_null(MemberOps)) AddMethodCandidate(Method, Base, 0, 0, CandidateSet, /*SuppressUserConversions=*/false); diff --git a/test/SemaCXX/namespace.cpp b/test/SemaCXX/namespace.cpp index 848dc27671..7af25ec35f 100644 --- a/test/SemaCXX/namespace.cpp +++ b/test/SemaCXX/namespace.cpp @@ -9,7 +9,6 @@ int A; // expected-error {{redefinition of 'A' as different kind of symbol}} class A; // expected-error {{redefinition of 'A' as different kind of symbol}} class B {}; // expected-note {{previous definition is here}} -namespace B {} // expected-error {{redefinition of 'B' as different kind of symbol}} void C(); // expected-note {{previous definition is here}} namespace C {} // expected-error {{redefinition of 'C' as different kind of symbol}} @@ -55,3 +54,5 @@ namespace S1 { } } } + +namespace B {} // expected-error {{redefinition of 'B' as different kind of symbol}} diff --git a/test/SemaCXX/qualified-id-lookup.cpp b/test/SemaCXX/qualified-id-lookup.cpp new file mode 100644 index 0000000000..ac2c693401 --- /dev/null +++ b/test/SemaCXX/qualified-id-lookup.cpp @@ -0,0 +1,53 @@ +// RUN: clang -fsyntax-only -verify %s + +namespace Ns { + int f(); // expected-note{{previous declaration is here}} +} +namespace Ns { + double f(); // expected-error{{functions that differ only in their return type cannot be overloaded}} +} + +namespace Ns2 { + float f(); +} + +namespace Ns2 { + float f(int); // expected-note{{previous declaration is here}} +} + +namespace Ns2 { + double f(int); // expected-error{{functions that differ only in their return type cannot be overloaded}} +} + +namespace N { + int& f1(); +} + +namespace N { + struct f1 { + static int member; + }; + + void test_f1() { + int &i1 = f1(); + } +} + +namespace N { + float& f1(int); + + struct f2 { + static int member; + }; + void f2(); +} + +int i1 = N::f1::member; +typedef struct N::f1 type1; +int i2 = N::f2::member; +typedef struct N::f2 type2; + +void test_f1(int i) { + int &v1 = N::f1(); + float &v2 = N::f1(i); +} -- 2.40.0