aboutsummaryrefslogtreecommitdiff
path: root/lib/Sema/SemaDecl.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Sema/SemaDecl.cpp')
-rw-r--r--lib/Sema/SemaDecl.cpp147
1 files changed, 135 insertions, 12 deletions
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))