diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h index 460e3de2282b..5623fe981ac7 100644 --- a/clang/include/clang/AST/Decl.h +++ b/clang/include/clang/AST/Decl.h @@ -900,7 +900,7 @@ protected: /// TagDecl - Represents the declaration of a struct/union/class/enum. -class TagDecl : public TypeDecl { +class TagDecl : public TypeDecl, public DeclContext { public: enum TagKind { TK_struct, @@ -919,7 +919,7 @@ private: protected: TagDecl(Kind DK, TagKind TK, DeclContext *DC, SourceLocation L, IdentifierInfo *Id, ScopedDecl *PrevDecl) - : TypeDecl(DK, DC, L, Id, PrevDecl) { + : TypeDecl(DK, DC, L, Id, PrevDecl), DeclContext(DK) { assert((DK != Enum || TK == TK_enum) &&"EnumDecl not matched with TK_enum"); TagDeclKind = TK; IsDefinition = false; @@ -970,7 +970,7 @@ protected: /// EnumDecl - Represents an enum. As an extension, we allow forward-declared /// enums. -class EnumDecl : public TagDecl, public DeclContext { +class EnumDecl : public TagDecl { /// 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. @@ -978,7 +978,7 @@ class EnumDecl : public TagDecl, public DeclContext { EnumDecl(DeclContext *DC, SourceLocation L, IdentifierInfo *Id, ScopedDecl *PrevDecl) - : TagDecl(Enum, TK_enum, DC, L, Id, PrevDecl), DeclContext(Enum) { + : TagDecl(Enum, TK_enum, DC, L, Id, PrevDecl) { IntegerType = QualType(); } public: @@ -1053,7 +1053,7 @@ 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, public DeclContext { +class RecordDecl : public TagDecl { /// 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. diff --git a/clang/include/clang/AST/DeclBase.h b/clang/include/clang/AST/DeclBase.h index 6780a33c5b64..689ae69c63b3 100644 --- a/clang/include/clang/AST/DeclBase.h +++ b/clang/include/clang/AST/DeclBase.h @@ -68,9 +68,9 @@ public: Namespace, // [DeclContext] // TypeDecl Typedef, - // TagDecl - Enum, // [DeclContext] - Record, // [DeclContext] + // TagDecl // [DeclContext] + Enum, + Record, CXXRecord, TemplateTypeParm, // ValueDecl @@ -206,9 +206,6 @@ public: case OriginalParmVar: case EnumConstant: case NonTypeTemplateParm: - case Field: - case ObjCAtDefsField: - case ObjCIvar: case ObjCInterface: case ObjCCompatibleAlias: case OverloadedFunction: @@ -216,6 +213,12 @@ public: case CXXConversion: case CXXClassVar: return IDNS_Ordinary; + + case Field: + case ObjCAtDefsField: + case ObjCIvar: + return IDNS_Member; + case Record: case CXXRecord: case TemplateTypeParm: diff --git a/clang/include/clang/Parse/Action.h b/clang/include/clang/Parse/Action.h index 5bba2a7b6df2..4c524f48d2df 100644 --- a/clang/include/clang/Parse/Action.h +++ b/clang/include/clang/Parse/Action.h @@ -341,10 +341,14 @@ public: SourceLocation LBrac, SourceLocation RBrac, AttributeList *AttrList) {} - /// ActOnEnumStartDefinition - Invoked when we have entered the - /// scope of the enumeration body and will be parsing its - /// enumerators. - virtual void ActOnEnumStartDefinition(Scope *S, DeclTy *EnumDecl) { } + /// ActOnTagStartDefinition - Invoked when we have entered the + /// scope of a tag's definition (e.g., for an enumeration, class, + /// struct, or union). + virtual void ActOnTagStartDefinition(Scope *S, DeclTy *TagDecl) { } + + /// ActOnTagFinishDefinition - Invoked once we have finished parsing + /// the definition of a tag (enumeration, class, struct, or union). + virtual void ActOnTagFinishDefinition(Scope *S, DeclTy *TagDecl) { } virtual DeclTy *ActOnEnumConstant(Scope *S, DeclTy *EnumDecl, DeclTy *LastEnumConstant, @@ -915,12 +919,6 @@ public: unsigned NumBases) { } - /// ActOnStartCXXClassDef - This is called at the start of a class/struct/union - /// definition, when on C++. - virtual void ActOnStartCXXClassDef(Scope *S, DeclTy *TagDecl, - SourceLocation LBrace) { - } - /// ActOnCXXMemberDeclarator - This is invoked when a C++ class member /// declarator is parsed. 'AS' is the access specifier, 'BitfieldWidth' /// specifies the bitfield width if there is one and 'Init' specifies the @@ -962,11 +960,6 @@ public: SourceLocation RBrac) { } - /// ActOnFinishCXXClassDef - This is called when a class/struct/union has - /// completed parsing, when on C++. - virtual void ActOnFinishCXXClassDef(DeclTy *TagDecl) { - } - //===---------------------------C++ Templates----------------------------===// /// ActOnTypeParameter - Called when a C++ template type parameter diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp index b3f19a25b860..8521b9b44ead 100644 --- a/clang/lib/AST/Decl.cpp +++ b/clang/lib/AST/Decl.cpp @@ -314,8 +314,7 @@ 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), DeclContext(DK) { - + : TagDecl(DK, TK, DC, L, Id, 0) { HasFlexibleArrayMember = false; AnonymousStructOrUnion = false; assert(classof(static_cast(this)) && "Invalid Kind!"); diff --git a/clang/lib/AST/DeclBase.cpp b/clang/lib/AST/DeclBase.cpp index 49890144a956..83f8fa411f93 100644 --- a/clang/lib/AST/DeclBase.cpp +++ b/clang/lib/AST/DeclBase.cpp @@ -579,6 +579,7 @@ DeclContext::lookup(DeclarationName Name) const { const DeclContext *DeclContext::getLookupContext() const { const DeclContext *Ctx = this; + // Skip through transparent contexts. while (Ctx->isTransparentContext()) Ctx = Ctx->getParent(); return Ctx; diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index c4126f3bb46d..219295fa74d8 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -948,6 +948,9 @@ void Parser::ParseStructUnionBody(SourceLocation RecordLoc, unsigned TagType, DeclTy *TagDecl) { SourceLocation LBraceLoc = ConsumeBrace(); + ParseScope StructScope(this, Scope::DeclScope); + Actions.ActOnTagStartDefinition(CurScope, TagDecl); + // Empty structs are an extension in C (C99 6.7.2.1p7), but are allowed in // C++. if (Tok.is(tok::r_brace) && !getLang().CPlusPlus) @@ -1027,7 +1030,9 @@ void Parser::ParseStructUnionBody(SourceLocation RecordLoc, Actions.ActOnFields(CurScope, RecordLoc,TagDecl,&FieldDecls[0],FieldDecls.size(), LBraceLoc, RBraceLoc, - AttrList); + AttrList); + StructScope.Exit(); + Actions.ActOnTagFinishDefinition(CurScope, TagDecl); } @@ -1125,7 +1130,7 @@ void Parser::ParseEnumSpecifier(DeclSpec &DS) { void Parser::ParseEnumBody(SourceLocation StartLoc, DeclTy *EnumDecl) { // Enter the scope of the enum body and start the definition. ParseScope EnumScope(this, Scope::DeclScope); - Actions.ActOnEnumStartDefinition(CurScope, EnumDecl); + Actions.ActOnTagStartDefinition(CurScope, EnumDecl); SourceLocation LBraceLoc = ConsumeBrace(); @@ -1178,6 +1183,9 @@ void Parser::ParseEnumBody(SourceLocation StartLoc, DeclTy *EnumDecl) { // If attributes exist after the identifier list, parse them. if (Tok.is(tok::kw___attribute)) AttrList = ParseAttributes(); // FIXME: where do they do? + + EnumScope.Exit(); + Actions.ActOnTagFinishDefinition(CurScope, EnumDecl); } /// isTypeSpecifierQualifier - Return true if the current token could be the diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp index 81ea52ca690e..c6c2ae4cfe18 100644 --- a/clang/lib/Parse/ParseDeclCXX.cpp +++ b/clang/lib/Parse/ParseDeclCXX.cpp @@ -730,7 +730,7 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc, // Enter a scope for the class. ParseScope ClassScope(this, Scope::CXXClassScope|Scope::DeclScope); - Actions.ActOnStartCXXClassDef(CurScope, TagDecl, LBraceLoc); + Actions.ActOnTagStartDefinition(CurScope, TagDecl); // C++ 11p3: Members of a class defined with the keyword class are private // by default. Members of a class defined with the keywords struct or union @@ -802,7 +802,7 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc, // Leave the class scope. ClassScope.Exit(); - Actions.ActOnFinishCXXClassDef(TagDecl); + Actions.ActOnTagFinishDefinition(CurScope, TagDecl); } /// ParseConstructorInitializer - Parse a C++ constructor initializer, diff --git a/clang/lib/Parse/ParseObjc.cpp b/clang/lib/Parse/ParseObjc.cpp index 759de7a0648d..cc13a5e0ae18 100644 --- a/clang/lib/Parse/ParseObjc.cpp +++ b/clang/lib/Parse/ParseObjc.cpp @@ -840,6 +840,8 @@ void Parser::ParseObjCClassInstanceVariables(DeclTy *interfaceDecl, llvm::SmallVector AllIvarDecls; llvm::SmallVector FieldDeclarators; + ParseScope ClassScope(this, Scope::DeclScope); + SourceLocation LBraceLoc = ConsumeBrace(); // the "{" tok::ObjCKeywordKind visibility = tok::objc_protected; diff --git a/clang/lib/Sema/IdentifierResolver.cpp b/clang/lib/Sema/IdentifierResolver.cpp index 90906e72746e..762885e42c38 100644 --- a/clang/lib/Sema/IdentifierResolver.cpp +++ b/clang/lib/Sema/IdentifierResolver.cpp @@ -60,6 +60,9 @@ DeclContext *IdentifierResolver::LookupContext::getContext(Decl *D) { else return TUCtx(); + if (!Ctx) // FIXME: HACK! We shouldn't end up with a NULL context here. + return TUCtx(); + Ctx = Ctx->getLookupContext(); if (isa(Ctx)) diff --git a/clang/lib/Sema/Sema.h b/clang/lib/Sema/Sema.h index 765dfe5420ca..61be6445d129 100644 --- a/clang/lib/Sema/Sema.h +++ b/clang/lib/Sema/Sema.h @@ -327,7 +327,16 @@ public: DeclTy **Fields, unsigned NumFields, SourceLocation LBrac, SourceLocation RBrac, AttributeList *AttrList); - virtual void ActOnEnumStartDefinition(Scope *S, DeclTy *EnumDecl); + + /// ActOnTagStartDefinition - Invoked when we have entered the + /// scope of a tag's definition (e.g., for an enumeration, class, + /// struct, or union). + virtual void ActOnTagStartDefinition(Scope *S, DeclTy *TagDecl); + + /// ActOnTagFinishDefinition - Invoked once we have finished parsing + /// the definition of a tag (enumeration, class, struct, or union). + virtual void ActOnTagFinishDefinition(Scope *S, DeclTy *TagDecl); + virtual DeclTy *ActOnEnumConstant(Scope *S, DeclTy *EnumDecl, DeclTy *LastEnumConstant, SourceLocation IdLoc, IdentifierInfo *Id, @@ -1017,9 +1026,6 @@ public: virtual bool isCurrentClassName(const IdentifierInfo &II, Scope *S, const CXXScopeSpec *SS); - virtual void ActOnStartCXXClassDef(Scope *S, DeclTy *TagDecl, - SourceLocation LBrace); - virtual DeclTy *ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D, ExprTy *BitfieldWidth, ExprTy *Init, DeclTy *LastInGroup); @@ -1040,8 +1046,6 @@ public: SourceLocation LBrac, SourceLocation RBrac); - virtual void ActOnFinishCXXClassDef(DeclTy *TagDecl); - virtual void ActOnStartDelayedCXXMethodDeclaration(Scope *S, DeclTy *Method); virtual void ActOnDelayedCXXMethodParameter(Scope *S, DeclTy *Param); virtual void ActOnFinishDelayedCXXMethodDeclaration(Scope *S, DeclTy *Method); diff --git a/clang/lib/Sema/SemaCXXScopeSpec.cpp b/clang/lib/Sema/SemaCXXScopeSpec.cpp index 5fb2740fcf31..dcb2a5fba551 100644 --- a/clang/lib/Sema/SemaCXXScopeSpec.cpp +++ b/clang/lib/Sema/SemaCXXScopeSpec.cpp @@ -28,7 +28,7 @@ namespace { DeclContext::lookup_const_iterator I, E; for (llvm::tie(I, E) = LookupCtx->lookup(Name); I != E; ++I) { IdIsUndeclared = false; - if (((*I)->getIdentifierNamespace() & Decl::IDNS_Tag) || + if (((*I)->isInIdentifierNamespace(Decl::IDNS_Tag)) || isa(*I)) return *I; } diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 6585733ab38b..c6e4336a3dc8 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/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(SearchCtx) || isa(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(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(DC) || isa(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((Decl *)TagD); + + // Enter the tag context. + PushDeclContext(S, Tag); + + if (CXXRecordDecl *Record = dyn_cast(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((Decl *)TagD); + + if (isa(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(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(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(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 RecFields; - // FIXME: Eventually, we'd like to eliminate this in favor of - // checking for redeclarations on-the-fly. - llvm::DenseMap FieldIDs; - for (unsigned i = 0; i != NumFields; ++i) { FieldDecl *FD = cast_or_null(static_cast(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 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(Record)) - Consumer.HandleTagDeclDefinition(Record); } else { ObjCIvarDecl **ClsFields = reinterpret_cast(&RecFields[0]); if (ObjCInterfaceDecl *ID = dyn_cast(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((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, diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index edc3a28dcf5d..dea3688bdbfb 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -414,28 +414,6 @@ void Sema::ActOnBaseSpecifiers(DeclTy *ClassDecl, BaseTy **Bases, // C++ class member Handling //===----------------------------------------------------------------------===// -/// ActOnStartCXXClassDef - This is called at the start of a class/struct/union -/// definition, when on C++. -void Sema::ActOnStartCXXClassDef(Scope *S, DeclTy *D, SourceLocation LBrace) { - CXXRecordDecl *Dcl = cast(static_cast(D)); - PushDeclContext(S, Dcl); - FieldCollector->StartClass(); - - if (Dcl->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, Dcl->getTagKind(), - CurContext, Dcl->getLocation(), - Dcl->getIdentifier(), Dcl); - InjectedClassName->setImplicit(); - PushOnScopeChains(InjectedClassName, S); - } -} - /// ActOnCXXMemberDeclarator - This is invoked when a C++ class member /// declarator is parsed. 'AS' is the access specifier, 'BW' specifies the /// bitfield width if there is one and 'InitExpr' specifies the initializer if @@ -975,16 +953,6 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) { } } -void Sema::ActOnFinishCXXClassDef(DeclTy *D) { - CXXRecordDecl *Rec = cast(static_cast(D)); - FieldCollector->FinishClass(); - PopDeclContext(); - - // Everything, including inline method definitions, have been parsed. - // Let the consumer know of the new TagDecl definition. - Consumer.HandleTagDeclDefinition(Rec); -} - /// ActOnStartDelayedCXXMethodDeclaration - We have completed /// parsing a top-level (non-nested) C++ class, and we are now /// parsing those parts of the given Method declaration that could diff --git a/clang/test/Sema/member-reference.c b/clang/test/Sema/member-reference.c index 784d60020ad3..b434f5b77938 100644 --- a/clang/test/Sema/member-reference.c +++ b/clang/test/Sema/member-reference.c @@ -7,3 +7,14 @@ void f(void) { s->i = 1; } +typedef int x; +struct S { + int x; + x z; +}; + +void g(void) { + struct S s[1]; + s->x = 1; + s->z = 2; +} diff --git a/clang/test/Sema/nested-redef.c b/clang/test/Sema/nested-redef.c new file mode 100644 index 000000000000..83cd4209675c --- /dev/null +++ b/clang/test/Sema/nested-redef.c @@ -0,0 +1,22 @@ +// RUN: clang -fsyntax-only -verify %s +struct X { // expected-note{{previous definition is here}} + struct X { } x; // expected-error{{nested redefinition of 'X'}} +}; + +struct Y { }; +void f(void) { + struct Y { }; // okay: this is a different Y +} + +struct T; +struct Z { + struct T { int x; } t; + struct U { int x; } u; +}; + +void f2(void) { + struct T t; + // FIXME: this is well-formed, but Clang breaks on it struct U u; +} + + diff --git a/clang/test/SemaCXX/anonymous-union.cpp b/clang/test/SemaCXX/anonymous-union.cpp index a66745b37848..872c45c46897 100644 --- a/clang/test/SemaCXX/anonymous-union.cpp +++ b/clang/test/SemaCXX/anonymous-union.cpp @@ -66,7 +66,7 @@ struct Redecl { union { int x; // expected-error{{member of anonymous union redeclares 'x'}} float y; - double z; // expected-note{{previous definition is here}} + double z; // expected-note{{previous declaration is here}} double zz; // expected-note{{previous definition is here}} }; diff --git a/clang/test/SemaCXX/class.cpp b/clang/test/SemaCXX/class.cpp index 7e06415a09da..d739af87dd79 100644 --- a/clang/test/SemaCXX/class.cpp +++ b/clang/test/SemaCXX/class.cpp @@ -53,7 +53,7 @@ public: typedef int A; - virtual int vi; // expected-error {{error: 'virtual' can only appear on non-static member functions}} + virtual int viv; // expected-error {{error: 'virtual' can only appear on non-static member functions}} virtual static int vsif(); // expected-error {{error: 'virtual' can only appear on non-static member functions}} virtual int vif(); @@ -105,3 +105,8 @@ void ogfn() struct C4; C4; // expected-error {{declaration does not declare anything}} } + +struct C4 { + void f(); // expected-note{{previous declaration is here}} + int f; // expected-error{{duplicate member 'f'}} +}; diff --git a/clang/test/SemaObjC/duplicate-ivar-check.m b/clang/test/SemaObjC/duplicate-ivar-check.m index ea42e9e277b7..6dcdc38dc300 100644 --- a/clang/test/SemaObjC/duplicate-ivar-check.m +++ b/clang/test/SemaObjC/duplicate-ivar-check.m @@ -2,13 +2,13 @@ @interface B1 { @public - double fill_B; // expected-note {{previous definition is here}} + double fill_B; // expected-note {{previous declaration is here}} } @end @interface B : B1 { @public - int one; // expected-note {{previous definition is here}} + int one; // expected-note {{previous declaration is here}} int one; // expected-error {{duplicate member 'one'}} } @end diff --git a/clang/test/SemaObjC/interface-scope.m b/clang/test/SemaObjC/interface-scope.m new file mode 100644 index 000000000000..8f164a9f7360 --- /dev/null +++ b/clang/test/SemaObjC/interface-scope.m @@ -0,0 +1,12 @@ +// RUN: clang -fsyntax-only -verify %s + +@interface I1 { +@private + int x; + struct { + unsigned int x : 3; + unsigned int y : 3; + } flags; + int y; +} +@end diff --git a/clang/test/SemaObjC/ivar-sem-check-1.m b/clang/test/SemaObjC/ivar-sem-check-1.m index 3416b31112ac..a6d1a22a9157 100644 --- a/clang/test/SemaObjC/ivar-sem-check-1.m +++ b/clang/test/SemaObjC/ivar-sem-check-1.m @@ -12,7 +12,7 @@ typedef int FOO(); struct T {} X; // expected-error {{nested redefinition of 'T'}} }YYY; FOO BADFUNC; // expected-error {{field 'BADFUNC' declared as a function}} - int kaka; // expected-note {{previous definition is here}} + int kaka; // expected-note {{previous declaration is here}} int kaka; // expected-error {{duplicate member 'kaka'}} char ch[]; // expected-error {{field 'ch' has incomplete type}} }