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.cpp201
1 files changed, 122 insertions, 79 deletions
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index 6585733ab3..c6e4336a3d 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -263,18 +263,37 @@ Decl *Sema::LookupDecl(DeclarationName Name, unsigned NSI, Scope *S,
bool NamespaceNameOnly) {
if (!Name) return 0;
unsigned NS = NSI;
- if (getLangOptions().CPlusPlus && (NS & Decl::IDNS_Ordinary))
- NS |= Decl::IDNS_Tag;
-
- if (LookupCtx == 0 &&
- (!getLangOptions().CPlusPlus || (NS == Decl::IDNS_Label))) {
- // Unqualified name lookup in C/Objective-C and name lookup for
- // labels in C++ is purely lexical, so search in the
- // declarations attached to the name.
+
+ // In C++, ordinary and member lookup will always find all
+ // kinds of names.
+ if (getLangOptions().CPlusPlus &&
+ (NS & (Decl::IDNS_Ordinary | Decl::IDNS_Member)))
+ NS |= Decl::IDNS_Tag | Decl::IDNS_Member | Decl::IDNS_Ordinary;
+
+ if (LookupCtx == 0 && !getLangOptions().CPlusPlus) {
+ // Unqualified name lookup in C/Objective-C is purely lexical, so
+ // search in the declarations attached to the name.
assert(!LookupCtx && "Can't perform qualified name lookup here");
assert(!NamespaceNameOnly && "Can't perform namespace name lookup here");
+
+ // For the purposes of unqualified name lookup, structs and unions
+ // don't have scopes at all. For example:
+ //
+ // struct X {
+ // struct T { int i; } x;
+ // };
+ //
+ // void f() {
+ // struct T t; // okay: T is defined lexically within X, but
+ // // semantically at global scope
+ // };
+ //
+ // FIXME: Is there a better way to deal with this?
+ DeclContext *SearchCtx = CurContext;
+ while (isa<RecordDecl>(SearchCtx) || isa<EnumDecl>(SearchCtx))
+ SearchCtx = SearchCtx->getParent();
IdentifierResolver::iterator I
- = IdResolver.begin(Name, CurContext, LookInParent);
+ = IdResolver.begin(Name, SearchCtx, LookInParent);
// Scan up the scope chain looking for a decl that matches this
// identifier that is in the appropriate namespace. This search
@@ -284,6 +303,11 @@ Decl *Sema::LookupDecl(DeclarationName Name, unsigned NSI, Scope *S,
if ((*I)->isInIdentifierNamespace(NS))
return *I;
} else if (LookupCtx) {
+ // If we're performing qualified name lookup (e.g., lookup into a
+ // struct), find fields as part of ordinary name lookup.
+ if (NS & Decl::IDNS_Ordinary)
+ NS |= Decl::IDNS_Member;
+
// Perform qualified name lookup into the LookupCtx.
// FIXME: Will need to look into base classes and such.
DeclContext::lookup_const_iterator I, E;
@@ -2852,6 +2876,15 @@ Sema::DeclTy *Sema::ActOnTag(Scope *S, unsigned TagType, TagKind TK,
// declaration or definition.
// Use ScopedDecl instead of TagDecl, because a NamespaceDecl may come up.
PrevDecl = dyn_cast_or_null<ScopedDecl>(LookupDecl(Name, Decl::IDNS_Tag,S));
+
+ if (!getLangOptions().CPlusPlus && TK != TK_Reference) {
+ // FIXME: This makes sure that we ignore the contexts associated
+ // with C structs, unions, and enums when looking for a matching
+ // tag declaration or definition. See the similar lookup tweak
+ // in Sema::LookupDecl; is there a better way to deal with this?
+ while (isa<RecordDecl>(DC) || isa<EnumDecl>(DC))
+ DC = DC->getParent();
+ }
}
if (PrevDecl && PrevDecl->isTemplateParameter()) {
@@ -3007,6 +3040,43 @@ CreateNewDecl:
return New;
}
+void Sema::ActOnTagStartDefinition(Scope *S, DeclTy *TagD) {
+ TagDecl *Tag = cast<TagDecl>((Decl *)TagD);
+
+ // Enter the tag context.
+ PushDeclContext(S, Tag);
+
+ if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(Tag)) {
+ FieldCollector->StartClass();
+
+ if (Record->getIdentifier()) {
+ // C++ [class]p2:
+ // [...] The class-name is also inserted into the scope of the
+ // class itself; this is known as the injected-class-name. For
+ // purposes of access checking, the injected-class-name is treated
+ // as if it were a public member name.
+ RecordDecl *InjectedClassName
+ = CXXRecordDecl::Create(Context, Record->getTagKind(),
+ CurContext, Record->getLocation(),
+ Record->getIdentifier(), Record);
+ InjectedClassName->setImplicit();
+ PushOnScopeChains(InjectedClassName, S);
+ }
+ }
+}
+
+void Sema::ActOnTagFinishDefinition(Scope *S, DeclTy *TagD) {
+ TagDecl *Tag = cast<TagDecl>((Decl *)TagD);
+
+ if (isa<CXXRecordDecl>(Tag))
+ FieldCollector->FinishClass();
+
+ // Exit this scope of this tag's definition.
+ PopDeclContext();
+
+ // Notify the consumer that we've defined a tag.
+ Consumer.HandleTagDeclDefinition(Tag);
+}
/// TryToFixInvalidVariablyModifiedType - Helper method to turn variable array
/// types into constant array types in certain situations which would otherwise
@@ -3108,6 +3178,18 @@ Sema::DeclTy *Sema::ActOnField(Scope *S, DeclTy *TagD,
DeclSpec::SCS_mutable,
/*PrevDecl=*/0);
+ if (II) {
+ Decl *PrevDecl
+ = LookupDecl(II, Decl::IDNS_Member, S, 0, false, false, false);
+ if (PrevDecl && isDeclInScope(PrevDecl, CurContext, S)
+ && !isa<TagDecl>(PrevDecl)) {
+ Diag(Loc, diag::err_duplicate_member) << II;
+ Diag(PrevDecl->getLocation(), diag::note_previous_declaration);
+ NewFD->setInvalidDecl();
+ Record->setInvalidDecl();
+ }
+ }
+
if (getLangOptions().CPlusPlus) {
CheckExtraCXXDefaultArguments(D);
if (!T->isPODType())
@@ -3119,9 +3201,9 @@ Sema::DeclTy *Sema::ActOnField(Scope *S, DeclTy *TagD,
if (D.getInvalidType() || InvalidDecl)
NewFD->setInvalidDecl();
- if (II && getLangOptions().CPlusPlus)
+ if (II) {
PushOnScopeChains(NewFD, S);
- else
+ } else
Record->addDecl(Context, NewFD);
return NewFD;
@@ -3146,6 +3228,7 @@ Sema::DeclTy *Sema::ActOnIvar(Scope *S,
SourceLocation DeclStart,
Declarator &D, ExprTy *BitfieldWidth,
tok::ObjCKeywordKind Visibility) {
+
IdentifierInfo *II = D.getIdentifier();
Expr *BitWidth = (Expr*)BitfieldWidth;
SourceLocation Loc = DeclStart;
@@ -3188,12 +3271,30 @@ Sema::DeclTy *Sema::ActOnIvar(Scope *S,
ObjCIvarDecl *NewID = ObjCIvarDecl::Create(Context, Loc, II, T, ac,
(Expr *)BitfieldWidth);
+ if (II) {
+ Decl *PrevDecl
+ = LookupDecl(II, Decl::IDNS_Member, S, 0, false, false, false);
+ if (PrevDecl && isDeclInScope(PrevDecl, CurContext, S)
+ && !isa<TagDecl>(PrevDecl)) {
+ Diag(Loc, diag::err_duplicate_member) << II;
+ Diag(PrevDecl->getLocation(), diag::note_previous_declaration);
+ NewID->setInvalidDecl();
+ }
+ }
+
// Process attributes attached to the ivar.
ProcessDeclAttributes(NewID, D);
if (D.getInvalidType() || InvalidDecl)
NewID->setInvalidDecl();
+ if (II) {
+ // FIXME: When interfaces are DeclContexts, we'll need to add
+ // these to the interface.
+ S->AddDecl(NewID);
+ IdResolver.AddDecl(NewID);
+ }
+
return NewID;
}
@@ -3206,27 +3307,26 @@ void Sema::ActOnFields(Scope* S,
assert(EnclosingDecl && "missing record or interface decl");
RecordDecl *Record = dyn_cast<RecordDecl>(EnclosingDecl);
- if (Record)
- if (RecordDecl* DefRecord = Record->getDefinition(Context)) {
+ 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(DefRecord->getLocation(), diag::err_nested_redefinition)
- << DefRecord->getDeclName();
+ 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;
- // FIXME: Eventually, we'd like to eliminate this in favor of
- // checking for redeclarations on-the-fly.
- llvm::DenseMap<const IdentifierInfo*, FieldDecl *> FieldIDs;
-
for (unsigned i = 0; i != NumFields; ++i) {
FieldDecl *FD = cast_or_null<FieldDecl>(static_cast<Decl*>(Fields[i]));
assert(FD && "missing field decl");
@@ -3234,37 +3334,7 @@ void Sema::ActOnFields(Scope* S,
// Get the type for the field.
Type *FDTy = FD->getType().getTypePtr();
- if (FD->isAnonymousStructOrUnion()) {
- // We have found a field that represents an anonymous struct
- // or union. Introduce all of the inner fields (recursively)
- // into the list of fields we know about, so that we can produce
- // an appropriate error message in cases like:
- //
- // struct X {
- // union {
- // int x;
- // float f;
- // };
- // double x;
- // };
- llvm::SmallVector<FieldDecl *, 4> AnonStructUnionFields;
- AnonStructUnionFields.push_back(FD);
- while (!AnonStructUnionFields.empty()) {
- FieldDecl *AnonField = AnonStructUnionFields.back();
- AnonStructUnionFields.pop_back();
-
- RecordDecl *AnonRecord
- = AnonField->getType()->getAsRecordType()->getDecl();
- for (RecordDecl::field_iterator F = AnonRecord->field_begin(),
- FEnd = AnonRecord->field_end();
- F != FEnd; ++F) {
- if ((*F)->isAnonymousStructOrUnion())
- AnonStructUnionFields.push_back(*F);
- else if (const IdentifierInfo *II = (*F)->getIdentifier())
- FieldIDs[II] = *F;
- }
- }
- } else {
+ if (!FD->isAnonymousStructOrUnion()) {
// Remember all fields written by the user.
RecFields.push_back(FD);
}
@@ -3340,28 +3410,13 @@ void Sema::ActOnFields(Scope* S,
continue;
}
// Keep track of the number of named members.
- if (IdentifierInfo *II = FD->getIdentifier()) {
- // Detect duplicate member names.
- if (FieldIDs[II]) {
- Diag(FD->getLocation(), diag::err_duplicate_member) << II;
- // Find the previous decl.
- Diag(FieldIDs[II]->getLocation(), diag::note_previous_definition);
- FD->setInvalidDecl();
- EnclosingDecl->setInvalidDecl();
- continue;
- }
+ if (FD->getIdentifier())
++NumNamedMembers;
- FieldIDs[II] = FD;
- }
}
// Okay, we successfully defined 'Record'.
if (Record) {
Record->completeDefinition(Context);
- // If this is a C++ record, HandleTagDeclDefinition will be invoked in
- // Sema::ActOnFinishCXXClassDef.
- if (!isa<CXXRecordDecl>(Record))
- Consumer.HandleTagDeclDefinition(Record);
} else {
ObjCIvarDecl **ClsFields = reinterpret_cast<ObjCIvarDecl**>(&RecFields[0]);
if (ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(EnclosingDecl)) {
@@ -3376,7 +3431,7 @@ void Sema::ActOnFields(Scope* S,
ObjCIvarDecl* prevIvar = ID->getSuperClass()->FindIvarDeclaration(II);
if (prevIvar) {
Diag(Ivar->getLocation(), diag::err_duplicate_member) << II;
- Diag(prevIvar->getLocation(), diag::note_previous_definition);
+ Diag(prevIvar->getLocation(), diag::note_previous_declaration);
}
}
}
@@ -3393,13 +3448,6 @@ void Sema::ActOnFields(Scope* S,
ProcessDeclAttributeList(Record, Attr);
}
-void Sema::ActOnEnumStartDefinition(Scope *S, DeclTy *EnumD) {
- EnumDecl *Enum = cast<EnumDecl>((Decl *)EnumD);
-
- // Enter the enumeration context.
- PushDeclContext(S, Enum);
-}
-
Sema::DeclTy *Sema::ActOnEnumConstant(Scope *S, DeclTy *theEnumDecl,
DeclTy *lastEnumConst,
SourceLocation IdLoc, IdentifierInfo *Id,
@@ -3507,7 +3555,6 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, DeclTy *EnumDeclX,
<< Enum->getDeclName();
Diag(Enum->getLocation(), diag::note_previous_definition);
Enum->setInvalidDecl();
- PopDeclContext();
return;
}
@@ -3675,10 +3722,6 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, DeclTy *EnumDeclX,
}
Enum->completeDefinition(Context, BestType);
- Consumer.HandleTagDeclDefinition(Enum);
-
- // Leave the context of the enumeration.
- PopDeclContext();
}
Sema::DeclTy *Sema::ActOnFileScopeAsmDecl(SourceLocation Loc,