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).

llvm-svn: 60878
This commit is contained in:
Douglas Gregor 2008-12-11 16:49:14 +00:00
parent 32bfb5de34
commit 91f84216f7
43 changed files with 1233 additions and 547 deletions

View File

@ -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<DeclTy*> &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;

View File

@ -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) {
SuperStructDecl->addDecl(*Context,
FieldDecl::Create(*Context, SuperStructDecl,
SourceLocation(), 0,
FieldTypes[i], /*BitWidth=*/0,
/*Mutable=*/false, 0),
true);
}
for (unsigned i = 0; i < 2; ++i)
FieldDecls[i] = FieldDecl::Create(*Context, SourceLocation(), 0,
FieldTypes[i]);
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());

View File

@ -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.

View File

@ -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<uintptr_t>(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<EnumConstantDecl>(DeclContext::decl_iterator::operator*());
}
pointer operator->() const {
return cast<EnumConstantDecl>(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<EnumConstantDecl>(getDeclChain());
}
const EnumConstantDecl *getEnumConstantList() const {
return cast_or_null<const EnumConstantDecl>(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<RecordDecl>(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;
field_iterator field_begin() {
assert(isDefinition() && "Not a definition!");
return Members;
/// 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<FieldDecl>(*Current))
++Current;
}
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<FieldDecl>(*Current); }
pointer operator->() const { return cast<FieldDecl>(*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_iterator field_end() {
assert(isDefinition() && "Not a definition!");
return Members + getNumMembers();
field_iterator field_end() const {
return field_iterator(decls_end(), decls_end());
}
field_const_iterator field_begin() const {
assert(isDefinition() && "Not a definition!");
return Members;
}
field_const_iterator field_end() const {
assert(isDefinition() && "Not a definition!");
return Members + getNumMembers();
}
/// 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;

View File

@ -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 <vector>
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<DeclarationName, TwoNamedDecls> 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<DeclarationName, TwoNamedDecls>.
llvm::PointerIntPair<void*, 3> LookupPtr;
/// Decls - Contains all of the declarations that are defined inside
/// this declaration context.
std::vector<ScopedDecl*> 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<NamespaceDecl*>(const_cast<From*>(D));
case Decl::Enum:
return static_cast<EnumDecl*>(const_cast<From*>(D));
case Decl::Record:
return static_cast<RecordDecl*>(const_cast<From*>(D));
case Decl::CXXRecord:
return static_cast<CXXRecordDecl*>(const_cast<From*>(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<ScopedDecl*>::const_iterator decl_iterator;
/// reverse_decl_iterator - Iterates through the declarations stored
/// within this context in reverse order.
typedef std::vector<ScopedDecl*>::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_iterator, lookup_iterator> lookup_result;
typedef std::pair<lookup_const_iterator, lookup_const_iterator>
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<class FromTy>
struct cast_convert_val< const ::clang::DeclContext, FromTy, FromTy> {
static const ::clang::DeclContext &doit(const FromTy &Val) {
return *FromTy::castToDeclContext(&Val);
}
};
template<class FromTy>
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<class ToTy>
struct cast_convert_val<ToTy,

View File

@ -116,8 +116,6 @@ public:
/// addOverload - Add an overloaded function FD to this set of
/// overloaded functions.
void addOverload(FunctionDecl *FD) {
assert((!getNumFunctions() || (FD->getDeclContext() == getDeclContext())) &&
"Overloaded functions must all be in the same context");
assert((FD->getDeclName() == getDeclName() ||
isa<CXXConversionDecl>(FD) || isa<CXXConstructorDecl>(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<const CXXFieldDecl>(RecordDecl::getMember(i));
}
CXXFieldDecl *getMember(unsigned i) {
return cast<CXXFieldDecl>(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<CXXFieldDecl>(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<CXXFieldDecl *>(BaseOrMember);
return reinterpret_cast<FieldDecl *>(BaseOrMember);
else
return 0;
}
@ -917,14 +877,14 @@ public:
if (ScopedDecl *SD = dyn_cast<ScopedDecl>(MD)) {
return cast<CXXRecordDecl>(SD->getDeclContext());
}
return cast<CXXFieldDecl>(MD)->getParent();
return cast<CXXRecordDecl>(cast<FieldDecl>(MD)->getDeclContext());
}
static bool isMember(Decl *D) {
if (ScopedDecl *SD = dyn_cast<ScopedDecl>(D)) {
return isa<CXXRecordDecl>(SD->getDeclContext());
}
return isa<CXXFieldDecl>(D);
return isa<FieldDecl>(D);
}
};

View File

@ -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);

View File

@ -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<void*>(Ptr); }
static DeclarationName getFromOpaqueInteger(uintptr_t P) {
DeclarationName N;
N.Ptr = P;

View File

@ -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<DeclTy*> &Decls) {}
virtual DeclTy *ActOnField(Scope *S, SourceLocation DeclStart,
virtual DeclTy *ActOnField(Scope *S, DeclTy *TagD, SourceLocation DeclStart,
Declarator &D, ExprTy *BitfieldWidth) {
return 0;
}

View File

@ -112,6 +112,12 @@ private:
typedef llvm::SmallPtrSet<Action::DeclTy*, 32> 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;
}
};

View File

@ -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<TagType>(D->TypeForDecl)->decl = D;
if (!D->TypeForDecl)
getTypeDeclType(D);
else
cast<TagType>(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);
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]);
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 =
RecordDecl::Create(*this, TagDecl::TK_struct, TUDecl, SourceLocation(),
&Idents.get("__objcFastEnumerationState"));
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<ASTContext*>(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);
}
}
}

View File

@ -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<FieldDecl>();
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<Decl*>(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
//===----------------------------------------------------------------------===//

View File

@ -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<DeclarationName, TwoNamedDecls> StoredDeclsMap;
DeclContext::~DeclContext() {
unsigned Size = LookupPtr.getInt();
if (Size == LookupIsMap) {
StoredDeclsMap *Map = static_cast<StoredDeclsMap*>(LookupPtr.getPointer());
delete Map;
} else {
NamedDecl **Array = static_cast<NamedDecl**>(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<NamespaceDecl*>(this)->getOriginalNamespace();
case Decl::Enum:
// The declaration associated with the enumeration type is our
// primary context.
return Context.getTypeDeclType(static_cast<EnumDecl*>(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<RecordDecl*>(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<NamespaceDecl*>(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<StoredDeclsMap*>(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<NamedDecl**>(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<DeclContext*>(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<NamedDecl **>(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<StoredDeclsMap*>(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;
}
}

View File

@ -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<CXXFieldDecl>();
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<uintptr_t>(Member);
assert((BaseOrMember & 0x01) == 0 && "Invalid member pointer");

View File

@ -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<ObjCAtDefsFieldDecl>();
return new (Mem) ObjCAtDefsFieldDecl(L, Id, T, BW);
return new (Mem) ObjCAtDefsFieldDecl(DC, L, Id, T, BW);
}
void ObjCAtDefsFieldDecl::Destroy(ASTContext& C) {

View File

@ -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<ScopedDecl>(D.ReadOwnedPtr<Decl>(C));
else
D.ReadPtr<ScopedDecl>(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<Decl>(getDeclContext())); // From ScopedDecl.
S.EmitPtr(cast_or_null<Decl>(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<EnumConstantDecl>(Elist));
Decl* next_declarator = D.ReadOwnedPtr<Decl>(C);
decl->setNextDeclarator(cast_or_null<ScopedDecl>(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>();
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<Expr>(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;
}

View File

@ -311,3 +311,9 @@ DeclarationNameTable::getCXXOperatorName(OverloadedOperatorKind Op) {
return DeclarationName(&CXXOperatorNames[(unsigned)Op]);
}
unsigned
llvm::DenseMapInfo<clang::DeclarationName>::
getHashValue(clang::DeclarationName N) {
return DenseMapInfo<void*>::getHashValue(N.getAsOpaquePtr());
}

View File

@ -353,7 +353,7 @@ static bool DeclCanBeLvalue(const NamedDecl *Decl, ASTContext &Ctx) {
= dyn_cast<NonTypeTemplateParmDecl>(Decl))
return NTTParm->getType()->isReferenceType();
return isa<VarDecl>(Decl) || isa<CXXFieldDecl>(Decl) ||
return isa<VarDecl>(Decl) || isa<FieldDecl>(Decl) ||
// C++ 3.10p2: An lvalue refers to an object or function.
(Ctx.getLangOptions().CPlusPlus &&
(isa<FunctionDecl>(Decl) || isa<OverloadedFunctionDecl>(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;
}

View File

@ -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;
}

View File

@ -433,8 +433,13 @@ SVal RegionStoreManager::RetrieveStruct(Store store, const TypedRegion* R) {
llvm::ImmutableList<SVal> 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<FieldDecl>(*Mem);
if (!FD)
continue;
FieldRegion* FR = MRMgr.getFieldRegion(FD, R);
RegionBindingsTy B(static_cast<const RegionBindingsTy::TreeTy*>(store));
RegionBindingsTy::data_type* data = B.lookup(FR);

View File

@ -289,10 +289,11 @@ llvm::DIType CGDebugInfo::CreateType(const EnumType *Ty,
llvm::SmallVector<llvm::DIDescriptor, 32> Enumerators;
// Create DIEnumerator elements for each enumerator.
for (EnumConstantDecl *Elt = Decl->getEnumConstantList(); Elt;
Elt = dyn_cast_or_null<EnumConstantDecl>(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.

View File

@ -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.

View File

@ -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;

View File

@ -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);

View File

@ -775,21 +775,20 @@ llvm::Function *CodeGenModule::getMemSetFn() {
static void appendFieldAndPadding(CodeGenModule &CGM,
std::vector<llvm::Constant*>& 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<llvm::StructType>(getTypes().ConvertType(CFTy));
std::vector<llvm::Constant*> 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);

View File

@ -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<const llvm::Type*> 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

View File

@ -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<DeclTy*, 16> 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);

View File

@ -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<CXXFieldDecl*, 32> Fields;
llvm::SmallVector<FieldDecl*, 32> 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() {

View File

@ -51,9 +51,6 @@ public:
DeclContext *IdentifierResolver::LookupContext::getContext(Decl *D) {
DeclContext *Ctx;
if (CXXFieldDecl *FD = dyn_cast<CXXFieldDecl>(D))
return FD->getParent();
if (EnumConstantDecl *EnumD = dyn_cast<EnumConstantDecl>(D)) {
Ctx = EnumD->getDeclContext()->getParent();
} else if (ScopedDecl *SD = dyn_cast<ScopedDecl>(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.

View File

@ -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);

View File

@ -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;"

View File

@ -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<DeclTy*> &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);

View File

@ -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<EnumDecl>(*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<TypedefDecl>(SD)) {

View File

@ -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<TagDecl>(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.
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);
IdResolver.AddShadowedDecl(TD, *I);
return;
// Add this declaration to the current context.
CurContext->addDecl(Context, TD);
return;
}
}
} else if (getLangOptions().CPlusPlus && isa<FunctionDecl>(D)) {
FunctionDecl *FD = cast<FunctionDecl>(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<OverloadedFunctionDecl>(*I) || isa<FunctionDecl>(*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<OverloadedFunctionDecl>(*I);
FunctionDecl *FD = cast<FunctionDecl>(D);
Decl *Prev = LookupDecl(FD->getDeclName(), Decl::IDNS_Ordinary, S,
FD->getDeclContext(), false, false);
if (Prev && (isa<OverloadedFunctionDecl>(Prev) || isa<FunctionDecl>(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<OverloadedFunctionDecl>(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<FunctionDecl>(*I));
Ovl->addOverload(dyn_cast<FunctionDecl>(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<ScopedDecl>(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<Decl*>(*I);
assert(TmpD && "This decl didn't get pushed??");
if (isa<CXXFieldDecl>(TmpD)) continue;
assert(isa<NamedDecl>(TmpD) && "Decl isn't NamedDecl?");
NamedDecl *D = cast<NamedDecl>(TmpD);
assert(isa<ScopedDecl>(TmpD) && "Decl isn't ScopedDecl?");
ScopedDecl *D = cast<ScopedDecl>(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<TemplateTypeParmDecl>(D))
IdResolver.RemoveDecl(D);
if (!D->getDeclName()) continue;
// Chain this decl to the containing DeclContext.
D->setNext(CurContext->getDeclChain());
CurContext->setDeclChain(D);
// 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<DeclContext *>(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<NamedDecl>(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<NamedDecl>(PrevDecl));
// declaration.
if (S->isDeclScope(PrevDecl)) {
IdResolver.RemoveDecl(cast<NamedDecl>(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<Sema::DeclTy*> &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<DeclTy*> &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<RecordDecl>((Decl*)TagD), Context, Decls);
// Introduce all of these fields into the appropriate scope.
for (llvm::SmallVectorImpl<DeclTy*>::iterator D = Decls.begin();
D != Decls.end(); ++D) {
FieldDecl *FD = cast<FieldDecl>((Decl*)*D);
if (getLangOptions().CPlusPlus)
PushOnScopeChains(cast<FieldDecl>(FD), S);
else if (RecordDecl *Record = dyn_cast<RecordDecl>((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<CXXRecordDecl>(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<CXXRecordDecl>(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);
}

View File

@ -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;
}

View File

@ -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<CXXRecordDecl>(static_cast<Decl *>(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<Decl*>(ActOnField(S, Loc, D, BitWidth));
Member = static_cast<Decl*>(ActOnField(S, cast<CXXRecordDecl>(CurContext),
Loc, D, BitWidth));
else
Member = static_cast<Decl*>(ActOnDeclarator(S, D, LastInGroup));
@ -593,7 +594,7 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D,
Member->setInvalidDecl();
if (isInstField) {
FieldCollector->Add(cast<CXXFieldDecl>(Member));
FieldCollector->Add(cast<FieldDecl>(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<FieldDecl>(*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);
LookupDecl(II, Decl::IDNS_Tag | Decl::IDNS_Ordinary, DeclRegionScope, 0,
/*enableLazyBuiltinCreation=*/false,
/*LookupInParent=*/false);
if (NamespaceDecl *OrigNS = dyn_cast_or_null<NamespaceDecl>(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());
if (PrevDecl && isDeclInScope(PrevDecl, CurContext, DeclRegionScope)) {
if (NamespaceDecl *OrigNS = dyn_cast<NamespaceDecl>(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.
// 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;
}

View File

@ -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.

View File

@ -453,13 +453,13 @@ Sema::ExprResult Sema::ActOnDeclarationNameExpr(Scope *S, SourceLocation Loc,
}
}
if (CXXFieldDecl *FD = dyn_cast<CXXFieldDecl>(D)) {
if (FieldDecl *FD = dyn_cast<FieldDecl>(D)) {
if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(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<CXXRecordDecl>(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<FieldDecl>(*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<CXXFieldDecl>(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<FieldDecl>(*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) {

View File

@ -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<FunctionDecl>(Decl))

View File

@ -15,6 +15,8 @@
#include "clang/AST/ASTContext.h"
#include "clang/AST/Expr.h"
#include "clang/Basic/Diagnostic.h"
#include <algorithm> // for std::count_if
#include <functional> // 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!)

View File

@ -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<CXXRecordType>(T1Rec)->getDecl(),
/*LookInParentCtx=*/false);
NamedDecl *MemberOps = (I == IdResolver.end())? 0 : *I;
DeclContext::lookup_const_result Lookup
= cast<CXXRecordType>(T1Rec)->getDecl()->lookup(Context, OpName);
NamedDecl *MemberOps = (Lookup.first == Lookup.second)? 0 : *Lookup.first;
if (CXXMethodDecl *Method = dyn_cast_or_null<CXXMethodDecl>(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<CXXRecordType>(Record)->getDecl(),
/*LookInParentCtx=*/false);
NamedDecl *MemberOps = (I == IdResolver.end())? 0 : *I;
DeclarationName OpName = Context.DeclarationNames.getCXXOperatorName(OO_Call);
DeclContext::lookup_const_result Lookup
= cast<CXXRecordType>(Record)->getDecl()->lookup(Context, OpName);
NamedDecl *MemberOps = (Lookup.first == Lookup.second)? 0 : *Lookup.first;
if (CXXMethodDecl *Method = dyn_cast_or_null<CXXMethodDecl>(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<CXXRecordType>(BaseRecord)->getDecl(),
/*LookInParentCtx=*/false);
NamedDecl *MemberOps = (I == IdResolver.end())? 0 : *I;
DeclContext::lookup_const_result Lookup
= cast<CXXRecordType>(BaseRecord)->getDecl()->lookup(Context, OpName);
NamedDecl *MemberOps = (Lookup.first == Lookup.second)? 0 : *Lookup.first;
if (CXXMethodDecl *Method = dyn_cast_or_null<CXXMethodDecl>(MemberOps))
AddMethodCandidate(Method, Base, 0, 0, CandidateSet,
/*SuppressUserConversions=*/false);

View File

@ -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}}

View File

@ -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);
}