aboutsummaryrefslogtreecommitdiff
path: root/lib/Sema/SemaDecl.cpp
diff options
context:
space:
mode:
authorDouglas Gregor <dgregor@apple.com>2009-01-17 00:42:38 +0000
committerDouglas Gregor <dgregor@apple.com>2009-01-17 00:42:38 +0000
commit0b7a158d120ac8d78c114a823e17eedfec6b6658 (patch)
tree06cb618c16a5c1e606f20e137a6be209ddb8bbe1 /lib/Sema/SemaDecl.cpp
parent41f2b32df5faff10c305ef1892fcb02846e4f489 (diff)
Teach DeclContext how to find the primary declaration for any TagDecl
even when we are still defining the TagDecl. This is required so that qualified name lookup of a class name within its definition works (see the new bits in test/SemaCXX/qualified-id-lookup.cpp). As part of this, move the nested redefinition checking code into ActOnTag. This gives us diagnostics earlier (when we try to perform the nested redefinition, rather than when we try to complete the 2nd definition) and removes some code duplication. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@62386 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Sema/SemaDecl.cpp')
-rw-r--r--lib/Sema/SemaDecl.cpp70
1 files changed, 33 insertions, 37 deletions
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index cfd33f6123..7346526265 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -2813,9 +2813,9 @@ TypedefDecl *Sema::ParseTypedefDecl(Scope *S, Declarator &D, QualType T,
/// ActOnTag - This is invoked when we see 'struct foo' or 'struct {'. In the
/// former case, Name will be non-null. In the later case, Name will be null.
-/// TagType indicates what kind of tag this is. TK indicates whether this is a
+/// TagSpec indicates what kind of tag this is. TK indicates whether this is a
/// reference/declaration/definition of a tag.
-Sema::DeclTy *Sema::ActOnTag(Scope *S, unsigned TagType, TagKind TK,
+Sema::DeclTy *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagKind TK,
SourceLocation KWLoc, const CXXScopeSpec &SS,
IdentifierInfo *Name, SourceLocation NameLoc,
AttributeList *Attr,
@@ -2825,7 +2825,7 @@ Sema::DeclTy *Sema::ActOnTag(Scope *S, unsigned TagType, TagKind TK,
"Nameless record must be a definition!");
TagDecl::TagKind Kind;
- switch (TagType) {
+ switch (TagSpec) {
default: assert(0 && "Unknown tag type!");
case DeclSpec::TST_struct: Kind = TagDecl::TK_struct; break;
case DeclSpec::TST_union: Kind = TagDecl::TK_union; break;
@@ -2838,6 +2838,8 @@ Sema::DeclTy *Sema::ActOnTag(Scope *S, unsigned TagType, TagKind TK,
DeclContext *LexicalContext = CurContext;
ScopedDecl *PrevDecl = 0;
+ bool Invalid = false;
+
if (Name && SS.isNotEmpty()) {
// We have a nested-name tag ('struct foo::bar').
@@ -2898,6 +2900,7 @@ Sema::DeclTy *Sema::ActOnTag(Scope *S, unsigned TagType, TagKind TK,
// Recover by making this an anonymous redefinition.
Name = 0;
PrevDecl = 0;
+ Invalid = true;
} else {
// If this is a use, just return the declaration we found.
@@ -2913,15 +2916,29 @@ Sema::DeclTy *Sema::ActOnTag(Scope *S, unsigned TagType, TagKind TK,
if (TagDecl *Def = PrevTagDecl->getDefinition(Context)) {
Diag(NameLoc, diag::err_redefinition) << Name;
Diag(Def->getLocation(), diag::note_previous_definition);
- // If this is a redefinition, recover by making this struct be
- // anonymous, which will make any later references get the 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;
+ Invalid = true;
+ } else {
+ // If the type is currently being defined, complain
+ // about a nested redefinition.
+ TagType *Tag = cast<TagType>(Context.getTagDeclType(PrevTagDecl));
+ if (Tag->isBeingDefined()) {
+ Diag(NameLoc, diag::err_nested_redefinition) << Name;
+ Diag(PrevTagDecl->getLocation(),
+ diag::note_previous_definition);
+ Name = 0;
+ PrevDecl = 0;
+ Invalid = true;
+ }
}
+
// Okay, this is definition of a previously declared or referenced
// tag PrevDecl. We're going to create a new Decl for it.
- }
+ }
}
// If we get here we have (another) forward declaration or we
// have a definition. Just create a new decl.
@@ -2944,6 +2961,7 @@ Sema::DeclTy *Sema::ActOnTag(Scope *S, unsigned TagType, TagKind TK,
Diag(PrevDecl->getLocation(), diag::note_previous_definition);
Name = 0;
PrevDecl = 0;
+ Invalid = true;
} else {
// The existing declaration isn't relevant to us; we're in a
// new scope, so clear out the previous declaration.
@@ -3034,16 +3052,23 @@ CreateNewDecl:
New->addAttr(new PackedAttr(Alignment * 8));
}
+ if (Invalid)
+ New->setInvalidDecl();
+
if (Attr)
ProcessDeclAttributeList(New, Attr);
- // If we're declaring or defining
+ // If we're declaring or defining a tag in function prototype scope
+ // in C, note that this type can only be used within the function.
if (Name && S->isFunctionPrototypeScope() && !getLangOptions().CPlusPlus)
Diag(Loc, diag::warn_decl_in_param_list) << Context.getTagDeclType(New);
// Set the lexical context. If the tag has a C++ scope specifier, the
// lexical context will be different from the semantic context.
New->setLexicalDeclContext(LexicalContext);
+
+ if (TK == TK_Definition)
+ New->startDefinition();
// If this has an identifier, add it to the scope stack.
if (Name) {
@@ -3332,22 +3357,6 @@ void Sema::ActOnFields(Scope* S,
assert(EnclosingDecl && "missing record or interface decl");
RecordDecl *Record = dyn_cast<RecordDecl>(EnclosingDecl);
- if (Record) {
- QualType RecordType = Context.getTypeDeclType(Record);
- if (RecordType->getAsRecordType()->getDecl()->isDefinition()) {
- RecordDecl *Def = RecordType->getAsRecordType()->getDecl();
- // Diagnose code like:
- // struct S { struct S {} X; };
- // We discover this when we complete the outer S. Reject and ignore the
- // outer S.
- Diag(Def->getLocation(), diag::err_nested_redefinition)
- << Def->getDeclName();
- Diag(RecLoc, diag::note_previous_definition);
- Record->setInvalidDecl();
- return;
- }
- }
-
// Verify that all the fields are okay.
unsigned NumNamedMembers = 0;
llvm::SmallVector<FieldDecl*, 32> RecFields;
@@ -3564,19 +3573,6 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, DeclTy *EnumDeclX,
EnumDecl *Enum = cast<EnumDecl>(static_cast<Decl*>(EnumDeclX));
QualType EnumType = Context.getTypeDeclType(Enum);
- if (EnumType->getAsEnumType()->getDecl()->isDefinition()) {
- EnumDecl *Def = EnumType->getAsEnumType()->getDecl();
- // Diagnose code like:
- // enum e0 {
- // E0 = sizeof(enum e0 { E1 })
- // };
- Diag(Def->getLocation(), diag::err_nested_redefinition)
- << Enum->getDeclName();
- Diag(Enum->getLocation(), diag::note_previous_definition);
- Enum->setInvalidDecl();
- return;
- }
-
// TODO: If the result value doesn't fit in an int, it must be a long or long
// long value. ISO C does not support this, but GCC does as an extension,
// emit a warning.