aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Driver/RewriteObjC.cpp4
-rw-r--r--include/clang/AST/ASTContext.h8
-rw-r--r--include/clang/AST/Decl.h25
-rw-r--r--include/clang/AST/DeclCXX.h3
-rw-r--r--include/clang/AST/Type.h1
-rw-r--r--lib/AST/ASTContext.cpp31
-rw-r--r--lib/AST/Decl.cpp25
-rw-r--r--lib/AST/DeclCXX.cpp133
-rw-r--r--lib/CodeGen/CGObjCMac.cpp2
-rw-r--r--lib/Sema/Sema.h5
-rw-r--r--lib/Sema/SemaDecl.cpp147
11 files changed, 288 insertions, 96 deletions
diff --git a/Driver/RewriteObjC.cpp b/Driver/RewriteObjC.cpp
index b078db3184..45ce8af6f7 100644
--- a/Driver/RewriteObjC.cpp
+++ b/Driver/RewriteObjC.cpp
@@ -1978,7 +1978,7 @@ QualType RewriteObjC::getSuperStructType() {
FieldDecls[i] = FieldDecl::Create(*Context, SourceLocation(), 0,
FieldTypes[i]);
- SuperStructDecl->defineBody(FieldDecls, 4);
+ SuperStructDecl->defineBody(*Context, FieldDecls, 4);
}
return Context->getTagDeclType(SuperStructDecl);
}
@@ -2005,7 +2005,7 @@ QualType RewriteObjC::getConstantStringStructType() {
FieldDecls[i] = FieldDecl::Create(*Context, SourceLocation(), 0,
FieldTypes[i]);
- ConstantStringDecl->defineBody(FieldDecls, 4);
+ ConstantStringDecl->defineBody(*Context, FieldDecls, 4);
}
return Context->getTagDeclType(ConstantStringDecl);
}
diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h
index 658085907c..7f0a757428 100644
--- a/include/clang/AST/ASTContext.h
+++ b/include/clang/AST/ASTContext.h
@@ -213,7 +213,7 @@ public:
/// getTypeDeclType - Return the unique reference to the type for
/// the specified type declaration.
- QualType getTypeDeclType(TypeDecl *Decl);
+ QualType getTypeDeclType(TypeDecl *Decl, TypeDecl* PrevDecl=0);
/// getTypedefType - Return the unique reference to the type for the
/// specified typename decl.
@@ -467,6 +467,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.
+ void setTagDefinition(TagDecl* R);
+ friend class RecordDecl;
};
} // end namespace clang
diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h
index 0e2db965f9..a13f0532da 100644
--- a/include/clang/AST/Decl.h
+++ b/include/clang/AST/Decl.h
@@ -690,6 +690,15 @@ public:
return IsDefinition;
}
+ /// getDefinition - Returns the TagDecl that actually defines this
+ /// struct/union/class/enum. When determining whether or not a
+ /// struct/union/class/enum is completely defined, one should use this method
+ /// as opposed to 'isDefinition'. 'isDefinition' indicates whether or not a
+ /// specific TagDecl is defining declaration, not whether or not the
+ /// struct/union/class/enum type is defined. This method returns NULL if
+ /// there is no TagDecl that defines the struct/union/class/enum.
+ TagDecl* getDefinition(ASTContext& C) const;
+
const char *getKindName() const {
switch (getTagKind()) {
default: assert(0 && "Unknown TagKind!");
@@ -806,13 +815,25 @@ protected:
public:
static RecordDecl *Create(ASTContext &C, TagKind TK, DeclContext *DC,
- SourceLocation L, IdentifierInfo *Id);
+ SourceLocation L, IdentifierInfo *Id,
+ RecordDecl* PrevDecl = 0);
virtual void Destroy(ASTContext& C);
bool hasFlexibleArrayMember() const { return HasFlexibleArrayMember; }
void setHasFlexibleArrayMember(bool V) { HasFlexibleArrayMember = V; }
+ /// getDefinition - Returns the RecordDecl that actually defines this
+ /// struct/union/class. When determining whether or not a struct/union/class
+ /// is completely defined, one should use this method as opposed to
+ /// 'isDefinition'. 'isDefinition' indicates whether or not a specific
+ /// RecordDecl is defining declaration, not whether or not the record
+ /// type is defined. This method returns NULL if there is no RecordDecl
+ /// that defines the struct/union/tag.
+ RecordDecl* getDefinition(ASTContext& C) const {
+ 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; }
@@ -844,7 +865,7 @@ public:
/// 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(FieldDecl **Members, unsigned numMembers);
+ 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;
diff --git a/include/clang/AST/DeclCXX.h b/include/clang/AST/DeclCXX.h
index 614e8ef93c..dc72267554 100644
--- a/include/clang/AST/DeclCXX.h
+++ b/include/clang/AST/DeclCXX.h
@@ -49,7 +49,8 @@ protected:
}
public:
static CXXRecordDecl *Create(ASTContext &C, TagKind TK, DeclContext *DC,
- SourceLocation L, IdentifierInfo *Id);
+ SourceLocation L, IdentifierInfo *Id,
+ CXXRecordDecl* PrevDecl=0);
const CXXFieldDecl *getMember(unsigned i) const {
return cast<const CXXFieldDecl>(RecordDecl::getMember(i));
diff --git a/include/clang/AST/Type.h b/include/clang/AST/Type.h
index 3eb28a86c0..50ea6f0836 100644
--- a/include/clang/AST/Type.h
+++ b/include/clang/AST/Type.h
@@ -1070,6 +1070,7 @@ public:
class TagType : public Type {
TagDecl *decl;
+ friend class ASTContext;
protected:
TagType(TagDecl *D, QualType can) : Type(Tagged, can), decl(D) {}
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index 5a6aa1ae31..4caf16c4b0 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -483,7 +483,8 @@ ASTContext::getASTObjCInterfaceLayout(const ObjCInterfaceDecl *D) {
/// specified record (struct/union/class), which indicates its size and field
/// position information.
const ASTRecordLayout &ASTContext::getASTRecordLayout(const RecordDecl *D) {
- assert(D->isDefinition() && "Cannot get layout of forward declarations!");
+ D = D->getDefinition(*this);
+ assert(D && "Cannot get layout of forward declarations!");
// Look up this layout, if already laid out, return what we have.
const ASTRecordLayout *&Entry = ASTRecordLayouts[D];
@@ -898,7 +899,7 @@ QualType ASTContext::getFunctionType(QualType ResultTy, const QualType *ArgArray
/// getTypeDeclType - Return the unique reference to the type for the
/// specified type declaration.
-QualType ASTContext::getTypeDeclType(TypeDecl *Decl) {
+QualType ASTContext::getTypeDeclType(TypeDecl *Decl, TypeDecl* PrevDecl) {
if (Decl->TypeForDecl) return QualType(Decl->TypeForDecl, 0);
if (TypedefDecl *Typedef = dyn_cast_or_null<TypedefDecl>(Decl))
@@ -907,19 +908,31 @@ QualType ASTContext::getTypeDeclType(TypeDecl *Decl) {
= dyn_cast_or_null<ObjCInterfaceDecl>(Decl))
return getObjCInterfaceType(ObjCInterface);
- if (CXXRecordDecl *CXXRecord = dyn_cast_or_null<CXXRecordDecl>(Decl))
- Decl->TypeForDecl = new CXXRecordType(CXXRecord);
- else if (RecordDecl *Record = dyn_cast_or_null<RecordDecl>(Decl))
- Decl->TypeForDecl = new RecordType(Record);
+ if (CXXRecordDecl *CXXRecord = dyn_cast_or_null<CXXRecordDecl>(Decl)) {
+ Decl->TypeForDecl = PrevDecl ? PrevDecl->TypeForDecl
+ : new CXXRecordType(CXXRecord);
+ }
+ else if (RecordDecl *Record = dyn_cast_or_null<RecordDecl>(Decl)) {
+ Decl->TypeForDecl = PrevDecl ? PrevDecl->TypeForDecl
+ : new RecordType(Record);
+ }
else if (EnumDecl *Enum = dyn_cast_or_null<EnumDecl>(Decl))
Decl->TypeForDecl = new EnumType(Enum);
else
assert(false && "TypeDecl without a type?");
- Types.push_back(Decl->TypeForDecl);
+ if (!PrevDecl) Types.push_back(Decl->TypeForDecl);
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.
+void ASTContext::setTagDefinition(TagDecl* D) {
+ assert (D->isDefinition());
+ cast<TagType>(D->TypeForDecl)->decl = D;
+}
+
/// getTypedefType - Return the unique reference to the type for the
/// specified typename decl.
QualType ASTContext::getTypedefType(TypedefDecl *Decl) {
@@ -1366,7 +1379,7 @@ QualType ASTContext::getCFConstantStringType() {
FieldDecls[i] = FieldDecl::Create(*this, SourceLocation(), 0,
FieldTypes[i]);
- CFConstantStringTypeDecl->defineBody(FieldDecls, 4);
+ CFConstantStringTypeDecl->defineBody(*this, FieldDecls, 4);
}
return getTagDeclType(CFConstantStringTypeDecl);
@@ -1392,7 +1405,7 @@ QualType ASTContext::getObjCFastEnumerationStateType()
RecordDecl::Create(*this, TagDecl::TK_struct, TUDecl, SourceLocation(),
&Idents.get("__objcFastEnumerationState"));
- ObjCFastEnumerationStateTypeDecl->defineBody(FieldDecls, 4);
+ ObjCFastEnumerationStateTypeDecl->defineBody(*this, FieldDecls, 4);
}
return getTagDeclType(ObjCFastEnumerationStateTypeDecl);
diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp
index eb9d0efdb4..8bc212d302 100644
--- a/lib/AST/Decl.cpp
+++ b/lib/AST/Decl.cpp
@@ -200,6 +200,16 @@ unsigned FunctionDecl::getMinRequiredArguments() const {
}
//===----------------------------------------------------------------------===//
+// TagdDecl Implementation
+//===----------------------------------------------------------------------===//
+
+TagDecl* TagDecl::getDefinition(ASTContext& C) const {
+ QualType T = C.getTypeDeclType(const_cast<TagDecl*>(this));
+ TagDecl* D = cast<TagDecl>(cast<TagType>(T)->getDecl());
+ return D->isDefinition() ? D : 0;
+}
+
+//===----------------------------------------------------------------------===//
// RecordDecl Implementation
//===----------------------------------------------------------------------===//
@@ -214,7 +224,8 @@ RecordDecl::RecordDecl(Kind DK, DeclContext *DC, SourceLocation L,
}
RecordDecl *RecordDecl::Create(ASTContext &C, TagKind TK, DeclContext *DC,
- SourceLocation L, IdentifierInfo *Id) {
+ SourceLocation L, IdentifierInfo *Id,
+ RecordDecl* PrevDecl) {
void *Mem = C.getAllocator().Allocate<RecordDecl>();
Kind DK;
@@ -225,7 +236,10 @@ RecordDecl *RecordDecl::Create(ASTContext &C, TagKind TK, DeclContext *DC,
case TK_union: DK = Union; break;
case TK_class: DK = Class; break;
}
- return new (Mem) RecordDecl(DK, DC, L, Id);
+
+ RecordDecl* R = new (Mem) RecordDecl(DK, DC, L, Id);
+ C.getTypeDeclType(R, PrevDecl);
+ return R;
}
RecordDecl::~RecordDecl() {
@@ -243,7 +257,8 @@ void RecordDecl::Destroy(ASTContext& 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(FieldDecl **members, unsigned numMembers) {
+void RecordDecl::defineBody(ASTContext& C, FieldDecl **members,
+ unsigned numMembers) {
assert(!isDefinition() && "Cannot redefine record!");
setDefinition(true);
NumMembers = numMembers;
@@ -251,8 +266,12 @@ void RecordDecl::defineBody(FieldDecl **members, unsigned numMembers) {
Members = new FieldDecl*[numMembers];
memcpy(Members, members, numMembers*sizeof(Decl*));
}
+
+ // Let ASTContext know that this is the defining RecordDecl this type.
+ C.setTagDefinition(this);
}
+
FieldDecl *RecordDecl::getMember(IdentifierInfo *II) {
if (Members == 0 || NumMembers < 0)
return 0;
diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp
index 0cce7db1d6..0a65ab34f0 100644
--- a/lib/AST/DeclCXX.cpp
+++ b/lib/AST/DeclCXX.cpp
@@ -1,65 +1,68 @@
-//===--- DeclCXX.cpp - C++ Declaration AST Node Implementation ------------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file implements the C++ related Decl classes.
-//
-//===----------------------------------------------------------------------===//
-
-#include "clang/AST/DeclCXX.h"
-#include "clang/AST/ASTContext.h"
-using namespace clang;
-
-//===----------------------------------------------------------------------===//
-// Decl Allocation/Deallocation Method Implementations
-//===----------------------------------------------------------------------===//
-
-CXXFieldDecl *CXXFieldDecl::Create(ASTContext &C, CXXRecordDecl *RD,
- SourceLocation L, IdentifierInfo *Id,
- QualType T, Expr *BW) {
- void *Mem = C.getAllocator().Allocate<CXXFieldDecl>();
- return new (Mem) CXXFieldDecl(RD, L, Id, T, BW);
-}
-
-CXXRecordDecl *CXXRecordDecl::Create(ASTContext &C, TagKind TK, DeclContext *DC,
- SourceLocation L, IdentifierInfo *Id) {
- Kind DK;
- switch (TK) {
- default: assert(0 && "Invalid TagKind!");
- case TK_enum: assert(0 && "Enum TagKind passed for Record!");
- case TK_struct: DK = CXXStruct; break;
- case TK_union: DK = CXXUnion; break;
- case TK_class: DK = CXXClass; break;
- }
- void *Mem = C.getAllocator().Allocate<CXXRecordDecl>();
- return new (Mem) CXXRecordDecl(DK, DC, L, Id);
-}
-
-CXXMethodDecl *
-CXXMethodDecl::Create(ASTContext &C, CXXRecordDecl *RD,
- SourceLocation L, IdentifierInfo *Id,
- QualType T, bool isStatic, bool isInline,
- ScopedDecl *PrevDecl) {
- void *Mem = C.getAllocator().Allocate<CXXMethodDecl>();
- return new (Mem) CXXMethodDecl(RD, L, Id, T, isStatic, isInline, PrevDecl);
-}
-
-QualType CXXMethodDecl::getThisType(ASTContext &C) const {
- assert(isInstance() && "No 'this' for static methods!");
- QualType ClassTy = C.getTagDeclType(cast<CXXRecordDecl>(getParent()));
- QualType ThisTy = C.getPointerType(ClassTy);
- ThisTy.addConst();
- return ThisTy;
-}
-
-CXXClassVarDecl *CXXClassVarDecl::Create(ASTContext &C, CXXRecordDecl *RD,
- SourceLocation L, IdentifierInfo *Id,
- QualType T, ScopedDecl *PrevDecl) {
- void *Mem = C.getAllocator().Allocate<CXXClassVarDecl>();
- return new (Mem) CXXClassVarDecl(RD, L, Id, T, PrevDecl);
-}
+//===--- DeclCXX.cpp - C++ Declaration AST Node Implementation ------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the C++ related Decl classes.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/ASTContext.h"
+using namespace clang;
+
+//===----------------------------------------------------------------------===//
+// Decl Allocation/Deallocation Method Implementations
+//===----------------------------------------------------------------------===//
+
+CXXFieldDecl *CXXFieldDecl::Create(ASTContext &C, CXXRecordDecl *RD,
+ SourceLocation L, IdentifierInfo *Id,
+ QualType T, Expr *BW) {
+ void *Mem = C.getAllocator().Allocate<CXXFieldDecl>();
+ return new (Mem) CXXFieldDecl(RD, L, Id, T, BW);
+}
+
+CXXRecordDecl *CXXRecordDecl::Create(ASTContext &C, TagKind TK, DeclContext *DC,
+ SourceLocation L, IdentifierInfo *Id,
+ CXXRecordDecl* PrevDecl) {
+ Kind DK;
+ switch (TK) {
+ default: assert(0 && "Invalid TagKind!");
+ case TK_enum: assert(0 && "Enum TagKind passed for Record!");
+ case TK_struct: DK = CXXStruct; break;
+ case TK_union: DK = CXXUnion; break;
+ case TK_class: DK = CXXClass; break;
+ }
+ void *Mem = C.getAllocator().Allocate<CXXRecordDecl>();
+ CXXRecordDecl* R = new (Mem) CXXRecordDecl(DK, DC, L, Id);
+ C.getTypeDeclType(R, PrevDecl);
+ return R;
+}
+
+CXXMethodDecl *
+CXXMethodDecl::Create(ASTContext &C, CXXRecordDecl *RD,
+ SourceLocation L, IdentifierInfo *Id,
+ QualType T, bool isStatic, bool isInline,
+ ScopedDecl *PrevDecl) {
+ void *Mem = C.getAllocator().Allocate<CXXMethodDecl>();
+ return new (Mem) CXXMethodDecl(RD, L, Id, T, isStatic, isInline, PrevDecl);
+}
+
+QualType CXXMethodDecl::getThisType(ASTContext &C) const {
+ assert(isInstance() && "No 'this' for static methods!");
+ QualType ClassTy = C.getTagDeclType(cast<CXXRecordDecl>(getParent()));
+ QualType ThisTy = C.getPointerType(ClassTy);
+ ThisTy.addConst();
+ return ThisTy;
+}
+
+CXXClassVarDecl *CXXClassVarDecl::Create(ASTContext &C, CXXRecordDecl *RD,
+ SourceLocation L, IdentifierInfo *Id,
+ QualType T, ScopedDecl *PrevDecl) {
+ void *Mem = C.getAllocator().Allocate<CXXClassVarDecl>();
+ return new (Mem) CXXClassVarDecl(RD, L, Id, T, PrevDecl);
+}
diff --git a/lib/CodeGen/CGObjCMac.cpp b/lib/CodeGen/CGObjCMac.cpp
index a535ea254e..3922ae66a3 100644
--- a/lib/CodeGen/CGObjCMac.cpp
+++ b/lib/CodeGen/CGObjCMac.cpp
@@ -1872,7 +1872,7 @@ ObjCTypesHelper::ObjCTypesHelper(CodeGen::CodeGenModule &cgm)
Ctx.getObjCIdType());
FieldDecls[1] = FieldDecl::Create(Ctx, SourceLocation(), 0,
Ctx.getObjCClassType());
- RD->defineBody(FieldDecls, 2);
+ RD->defineBody(Ctx, FieldDecls, 2);
SuperCTy = Ctx.getTagDeclType(RD);
SuperPtrCTy = Ctx.getPointerType(SuperCTy);
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index f5a85a5fc9..96f6e53c61 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -251,6 +251,11 @@ private:
virtual DeclTy *ActOnTag(Scope *S, unsigned TagType, TagKind TK,
SourceLocation KWLoc, IdentifierInfo *Name,
SourceLocation NameLoc, AttributeList *Attr);
+
+ DeclTy* ActOnTagStruct(Scope *S, TagDecl::TagKind Kind, TagKind TK,
+ SourceLocation KWLoc, IdentifierInfo *Name,
+ SourceLocation NameLoc, AttributeList *Attr);
+
virtual void ActOnDefs(Scope *S, SourceLocation DeclStart,
IdentifierInfo *ClassName,
llvm::SmallVectorImpl<DeclTy*> &Decls);
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index 467da81305..df91182383 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -1682,6 +1682,12 @@ Sema::DeclTy *Sema::ActOnTag(Scope *S, unsigned TagType, TagKind TK,
case DeclSpec::TST_enum: Kind = TagDecl::TK_enum; break;
}
+ // Two code paths: a new one for structs/unions/classes where we create
+ // separate decls for forward declarations, and an old (eventually to
+ // be removed) code path for enums.
+ if (Kind != TagDecl::TK_enum)
+ return ActOnTagStruct(S, Kind, TK, KWLoc, Name, NameLoc, Attr);
+
// If this is a named struct, check to see if there was a previous forward
// declaration or definition.
// Use ScopedDecl instead of TagDecl, because a NamespaceDecl may come up.
@@ -1781,6 +1787,121 @@ Sema::DeclTy *Sema::ActOnTag(Scope *S, unsigned TagType, TagKind TK,
return New;
}
+/// ActOnTagStruct - New "ActOnTag" logic for structs/unions/classes. Unlike
+/// the logic for enums, we create separate decls for forward declarations.
+/// This is called by ActOnTag, but eventually will replace its logic.
+Sema::DeclTy *Sema::ActOnTagStruct(Scope *S, TagDecl::TagKind Kind, TagKind TK,
+ SourceLocation KWLoc, IdentifierInfo *Name,
+ SourceLocation NameLoc, AttributeList *Attr) {
+
+ // If this is a named struct, check to see if there was a previous forward
+ // declaration or definition.
+ // Use ScopedDecl instead of TagDecl, because a NamespaceDecl may come up.
+ ScopedDecl *PrevDecl =
+ dyn_cast_or_null<ScopedDecl>(LookupDecl(Name, Decl::IDNS_Tag, S));
+
+ if (PrevDecl) {
+ assert((isa<TagDecl>(PrevDecl) || isa<NamespaceDecl>(PrevDecl)) &&
+ "unexpected Decl type");
+
+ if (TagDecl *PrevTagDecl = dyn_cast<TagDecl>(PrevDecl)) {
+ // If this is a use of a previous tag, or if the tag is already declared
+ // in the same scope (so that the definition/declaration completes or
+ // rementions the tag), reuse the decl.
+ if (TK == TK_Reference ||
+ IdResolver.isDeclInScope(PrevDecl, CurContext, S)) {
+ // Make sure that this wasn't declared as an enum and now used as a
+ // struct or something similar.
+ if (PrevTagDecl->getTagKind() != Kind) {
+ Diag(KWLoc, diag::err_use_with_wrong_tag, Name->getName());
+ Diag(PrevDecl->getLocation(), diag::err_previous_use);
+ // Recover by making this an anonymous redefinition.
+ Name = 0;
+ PrevDecl = 0;
+ } else {
+ // If this is a use, return the original decl.
+
+ // FIXME: In the future, return a variant or some other clue
+ // for the consumer of this Decl to know it doesn't own it.
+ // For our current ASTs this shouldn't be a problem, but will
+ // need to be changed with DeclGroups.
+ if (TK == TK_Reference)
+ return PrevDecl;
+
+ // The new decl is a definition?
+ if (TK == TK_Definition) {
+ // Diagnose attempts to redefine a tag.
+ if (RecordDecl* DefRecord =
+ cast<RecordDecl>(PrevTagDecl)->getDefinition(Context)) {
+ Diag(NameLoc, diag::err_redefinition, Name->getName());
+ Diag(DefRecord->getLocation(), diag::err_previous_definition);
+ // If this is a redefinition, recover by making this struct be
+ // anonymous, which will make any later references get the previous
+ // definition.
+ Name = 0;
+ PrevDecl = 0;
+ }
+ // Okay, this is definition of a previously declared or referenced
+ // tag. We're going to create a new Decl.
+ }
+ }
+ // If we get here we have (another) forward declaration. Just create
+ // a new decl.
+ }
+ else {
+ // If we get here, this is a definition of a new struct type in a nested
+ // scope, e.g. "struct foo; void bar() { struct foo; }", just create a
+ // new decl/type. We set PrevDecl to NULL so that the Records
+ // have distinct types.
+ PrevDecl = 0;
+ }
+ } else {
+ // PrevDecl is a namespace.
+ if (IdResolver.isDeclInScope(PrevDecl, CurContext, S)) {
+ // The tag name clashes with a namespace name, issue an error and
+ // recover by making this tag be anonymous.
+ Diag(NameLoc, diag::err_redefinition_different_kind, Name->getName());
+ Diag(PrevDecl->getLocation(), diag::err_previous_definition);
+ Name = 0;
+ }
+ }
+ }
+
+ // If there is an identifier, use the location of the identifier as the
+ // location of the decl, otherwise use the location of the struct/union
+ // keyword.
+ SourceLocation Loc = NameLoc.isValid() ? NameLoc : KWLoc;
+
+ // Otherwise, if this is the first time we've seen this tag, create the decl.
+ TagDecl *New;
+
+ // FIXME: Tag decls should be chained to any simultaneous vardecls, e.g.:
+ // struct X { int A; } D; D should chain to X.
+ if (getLangOptions().CPlusPlus)
+ New = CXXRecordDecl::Create(Context, Kind, CurContext, Loc, Name,
+ dyn_cast_or_null<CXXRecordDecl>(PrevDecl));
+ else
+ New = RecordDecl::Create(Context, Kind, CurContext, Loc, Name,
+ dyn_cast_or_null<RecordDecl>(PrevDecl));
+
+ // If this has an identifier, add it to the scope stack.
+ if ((TK == TK_Definition || !PrevDecl) && Name) {
+ // 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)
+ S = S->getParent();
+
+ // Add it to the decl chain.
+ PushOnScopeChains(New, S);
+ }
+
+ if (Attr)
+ ProcessDeclAttributeList(New, Attr);
+
+ return New;
+}
+
+
/// 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,
@@ -1977,17 +2098,19 @@ void Sema::ActOnFields(Scope* S,
assert(EnclosingDecl && "missing record or interface decl");
RecordDecl *Record = dyn_cast<RecordDecl>(EnclosingDecl);
- if (Record && Record->isDefinition()) {
- // Diagnose code like:
- // struct S { struct S {} X; };
- // We discover this when we complete the outer S. Reject and ignore the
- // outer S.
- Diag(Record->getLocation(), diag::err_nested_redefinition,
- Record->getKindName());
- Diag(RecLoc, diag::err_previous_definition);
- Record->setInvalidDecl();
- return;
- }
+ if (Record)
+ if (RecordDecl* DefRecord = Record->getDefinition(Context)) {
+ // Diagnose code like:
+ // struct S { struct S {} X; };
+ // We discover this when we complete the outer S. Reject and ignore the
+ // outer S.
+ Diag(DefRecord->getLocation(), diag::err_nested_redefinition,
+ DefRecord->getKindName());
+ Diag(RecLoc, diag::err_previous_definition);
+ Record->setInvalidDecl();
+ return;
+ }
+
// Verify that all the fields are okay.
unsigned NumNamedMembers = 0;
llvm::SmallVector<FieldDecl*, 32> RecFields;
@@ -2099,7 +2222,7 @@ void Sema::ActOnFields(Scope* S,
// Okay, we successfully defined 'Record'.
if (Record) {
- Record->defineBody(&RecFields[0], RecFields.size());
+ Record->defineBody(Context, &RecFields[0], RecFields.size());
// If this is a C++ record, HandleTagDeclDefinition will be invoked in
// Sema::ActOnFinishCXXClassDef.
if (!isa<CXXRecordDecl>(Record))