Hi Doug, My tester is pointing at this for a 2.1% slowdown at -fsyntax-only (on essentially Cocoa.h). Can you investigate?
- Daniel On Thu, Jan 8, 2009 at 12:45 PM, Douglas Gregor <[email protected]> wrote: > Author: dgregor > Date: Thu Jan 8 14:45:30 2009 > New Revision: 61940 > > URL: http://llvm.org/viewvc/llvm-project?rev=61940&view=rev > Log: > Unify the code for defining tags in C and C++, so that we always > introduce a Scope for the body of a tag. This reduces the number of > semantic differences between C and C++ structs and unions, and will > help with other features (e.g., anonymous unions) in C. Some important > points: > > - Fields are now in the "member" namespace (IDNS_Member), to keep > them separate from tags and ordinary names in C. See the new test > in Sema/member-reference.c for an example of why this matters. In > C++, ordinary and member name lookup will find members in both the > ordinary and member namespace, so the difference between > IDNS_Member and IDNS_Ordinary is erased by Sema::LookupDecl (but > only in C++!). > - We always introduce a Scope and push a DeclContext when we're > defining a tag, in both C and C++. Previously, we had different > actions and different Scope/CurContext behavior for enums, C > structs/unions, and C++ structs/unions/classes. Now, it's one pair > of actions. (Yay!) > > There's still some fuzziness in the handling of struct/union/enum > definitions within other struct/union/enum definitions in C. We'll > need to do some more cleanup to eliminate some reliance on CurContext > before we can solve this issue for real. What we want is for something > like this: > > struct X { > struct T { int x; } t; > }; > > to introduce T into translation unit scope (placing it at the > appropriate point in the IdentifierResolver chain, too), but it should > still have struct X as its lexical declaration > context. PushOnScopeChains isn't smart enough to do that yet, though, > so there's a FIXME test in nested-redef.c > > > Added: > cfe/trunk/test/Sema/nested-redef.c > cfe/trunk/test/SemaObjC/interface-scope.m > Modified: > cfe/trunk/include/clang/AST/Decl.h > cfe/trunk/include/clang/AST/DeclBase.h > cfe/trunk/include/clang/Parse/Action.h > cfe/trunk/lib/AST/Decl.cpp > cfe/trunk/lib/AST/DeclBase.cpp > cfe/trunk/lib/Parse/ParseDecl.cpp > cfe/trunk/lib/Parse/ParseDeclCXX.cpp > cfe/trunk/lib/Parse/ParseObjc.cpp > cfe/trunk/lib/Sema/IdentifierResolver.cpp > cfe/trunk/lib/Sema/Sema.h > cfe/trunk/lib/Sema/SemaCXXScopeSpec.cpp > cfe/trunk/lib/Sema/SemaDecl.cpp > cfe/trunk/lib/Sema/SemaDeclCXX.cpp > cfe/trunk/test/Sema/member-reference.c > cfe/trunk/test/SemaCXX/anonymous-union.cpp > cfe/trunk/test/SemaCXX/class.cpp > cfe/trunk/test/SemaObjC/duplicate-ivar-check.m > cfe/trunk/test/SemaObjC/ivar-sem-check-1.m > > Modified: cfe/trunk/include/clang/AST/Decl.h > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Decl.h?rev=61940&r1=61939&r2=61940&view=diff > > ============================================================================== > --- cfe/trunk/include/clang/AST/Decl.h (original) > +++ cfe/trunk/include/clang/AST/Decl.h Thu Jan 8 14:45:30 2009 > @@ -900,7 +900,7 @@ > > > /// 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 @@ > 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 @@ > > /// 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 @@ > > 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 @@ > /// 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. > > Modified: cfe/trunk/include/clang/AST/DeclBase.h > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclBase.h?rev=61940&r1=61939&r2=61940&view=diff > > ============================================================================== > --- cfe/trunk/include/clang/AST/DeclBase.h (original) > +++ cfe/trunk/include/clang/AST/DeclBase.h Thu Jan 8 14:45:30 2009 > @@ -68,9 +68,9 @@ > Namespace, // [DeclContext] > // TypeDecl > Typedef, > - // TagDecl > - Enum, // [DeclContext] > - Record, // [DeclContext] > + // TagDecl // [DeclContext] > + Enum, > + Record, > CXXRecord, > TemplateTypeParm, > // ValueDecl > @@ -206,9 +206,6 @@ > case OriginalParmVar: > case EnumConstant: > case NonTypeTemplateParm: > - case Field: > - case ObjCAtDefsField: > - case ObjCIvar: > case ObjCInterface: > case ObjCCompatibleAlias: > case OverloadedFunction: > @@ -216,6 +213,12 @@ > case CXXConversion: > case CXXClassVar: > return IDNS_Ordinary; > + > + case Field: > + case ObjCAtDefsField: > + case ObjCIvar: > + return IDNS_Member; > + > case Record: > case CXXRecord: > case TemplateTypeParm: > > Modified: cfe/trunk/include/clang/Parse/Action.h > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/Action.h?rev=61940&r1=61939&r2=61940&view=diff > > ============================================================================== > --- cfe/trunk/include/clang/Parse/Action.h (original) > +++ cfe/trunk/include/clang/Parse/Action.h Thu Jan 8 14:45:30 2009 > @@ -341,10 +341,14 @@ > 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 @@ > 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 @@ > 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 > > Modified: cfe/trunk/lib/AST/Decl.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Decl.cpp?rev=61940&r1=61939&r2=61940&view=diff > > ============================================================================== > --- cfe/trunk/lib/AST/Decl.cpp (original) > +++ cfe/trunk/lib/AST/Decl.cpp Thu Jan 8 14:45:30 2009 > @@ -314,8 +314,7 @@ > > 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<Decl*>(this)) && "Invalid Kind!"); > > Modified: cfe/trunk/lib/AST/DeclBase.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclBase.cpp?rev=61940&r1=61939&r2=61940&view=diff > > ============================================================================== > --- cfe/trunk/lib/AST/DeclBase.cpp (original) > +++ cfe/trunk/lib/AST/DeclBase.cpp Thu Jan 8 14:45:30 2009 > @@ -579,6 +579,7 @@ > > const DeclContext *DeclContext::getLookupContext() const { > const DeclContext *Ctx = this; > + // Skip through transparent contexts. > while (Ctx->isTransparentContext()) > Ctx = Ctx->getParent(); > return Ctx; > > Modified: cfe/trunk/lib/Parse/ParseDecl.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDecl.cpp?rev=61940&r1=61939&r2=61940&view=diff > > ============================================================================== > --- cfe/trunk/lib/Parse/ParseDecl.cpp (original) > +++ cfe/trunk/lib/Parse/ParseDecl.cpp Thu Jan 8 14:45:30 2009 > @@ -948,6 +948,9 @@ > 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 @@ > 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::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 @@ > // 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 > > Modified: cfe/trunk/lib/Parse/ParseDeclCXX.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDeclCXX.cpp?rev=61940&r1=61939&r2=61940&view=diff > > ============================================================================== > --- cfe/trunk/lib/Parse/ParseDeclCXX.cpp (original) > +++ cfe/trunk/lib/Parse/ParseDeclCXX.cpp Thu Jan 8 14:45:30 2009 > @@ -730,7 +730,7 @@ > // 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 @@ > // Leave the class scope. > ClassScope.Exit(); > > - Actions.ActOnFinishCXXClassDef(TagDecl); > + Actions.ActOnTagFinishDefinition(CurScope, TagDecl); > } > > /// ParseConstructorInitializer - Parse a C++ constructor initializer, > > Modified: cfe/trunk/lib/Parse/ParseObjc.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseObjc.cpp?rev=61940&r1=61939&r2=61940&view=diff > > ============================================================================== > --- cfe/trunk/lib/Parse/ParseObjc.cpp (original) > +++ cfe/trunk/lib/Parse/ParseObjc.cpp Thu Jan 8 14:45:30 2009 > @@ -840,6 +840,8 @@ > llvm::SmallVector<DeclTy*, 32> AllIvarDecls; > llvm::SmallVector<FieldDeclarator, 8> FieldDeclarators; > > + ParseScope ClassScope(this, Scope::DeclScope); > + > SourceLocation LBraceLoc = ConsumeBrace(); // the "{" > > tok::ObjCKeywordKind visibility = tok::objc_protected; > > Modified: cfe/trunk/lib/Sema/IdentifierResolver.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/IdentifierResolver.cpp?rev=61940&r1=61939&r2=61940&view=diff > > ============================================================================== > --- cfe/trunk/lib/Sema/IdentifierResolver.cpp (original) > +++ cfe/trunk/lib/Sema/IdentifierResolver.cpp Thu Jan 8 14:45:30 2009 > @@ -60,6 +60,9 @@ > else > return TUCtx(); > > + if (!Ctx) // FIXME: HACK! We shouldn't end up with a NULL context here. > + return TUCtx(); > + > Ctx = Ctx->getLookupContext(); > > if (isa<TranslationUnitDecl>(Ctx)) > > Modified: cfe/trunk/lib/Sema/Sema.h > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.h?rev=61940&r1=61939&r2=61940&view=diff > > ============================================================================== > --- cfe/trunk/lib/Sema/Sema.h (original) > +++ cfe/trunk/lib/Sema/Sema.h Thu Jan 8 14:45:30 2009 > @@ -327,7 +327,16 @@ > 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 @@ > 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 @@ > 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); > > Modified: cfe/trunk/lib/Sema/SemaCXXScopeSpec.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaCXXScopeSpec.cpp?rev=61940&r1=61939&r2=61940&view=diff > > ============================================================================== > --- cfe/trunk/lib/Sema/SemaCXXScopeSpec.cpp (original) > +++ cfe/trunk/lib/Sema/SemaCXXScopeSpec.cpp Thu Jan 8 14:45:30 2009 > @@ -28,7 +28,7 @@ > 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<TypedefDecl>(*I)) > return *I; > } > > Modified: cfe/trunk/lib/Sema/SemaDecl.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=61940&r1=61939&r2=61940&view=diff > > ============================================================================== > --- cfe/trunk/lib/Sema/SemaDecl.cpp (original) > +++ cfe/trunk/lib/Sema/SemaDecl.cpp Thu Jan 8 14:45:30 2009 > @@ -263,18 +263,37 @@ > 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 @@ > 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 @@ > // 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 @@ > 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 @@ > 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 @@ > 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 @@ > SourceLocation DeclStart, > Declarator &D, ExprTy *BitfieldWidth, > tok::ObjCKeywordKind Visibility) { > + > IdentifierInfo *II = D.getIdentifier(); > Expr *BitWidth = (Expr*)BitfieldWidth; > SourceLocation Loc = DeclStart; > @@ -3188,12 +3271,30 @@ > 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 @@ > 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 @@ > // 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 @@ > 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 @@ > 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 @@ > 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 @@ > << Enum->getDeclName(); > Diag(Enum->getLocation(), diag::note_previous_definition); > Enum->setInvalidDecl(); > - PopDeclContext(); > return; > } > > @@ -3675,10 +3722,6 @@ > } > > Enum->completeDefinition(Context, BestType); > - Consumer.HandleTagDeclDefinition(Enum); > - > - // Leave the context of the enumeration. > - PopDeclContext(); > } > > Sema::DeclTy *Sema::ActOnFileScopeAsmDecl(SourceLocation Loc, > > Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=61940&r1=61939&r2=61940&view=diff > > ============================================================================== > --- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original) > +++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Thu Jan 8 14:45:30 2009 > @@ -414,28 +414,6 @@ > // 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<CXXRecordDecl>(static_cast<Decl *>(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::ActOnFinishCXXClassDef(DeclTy *D) { > - CXXRecordDecl *Rec = cast<CXXRecordDecl>(static_cast<Decl *>(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 > > Modified: cfe/trunk/test/Sema/member-reference.c > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/member-reference.c?rev=61940&r1=61939&r2=61940&view=diff > > ============================================================================== > --- cfe/trunk/test/Sema/member-reference.c (original) > +++ cfe/trunk/test/Sema/member-reference.c Thu Jan 8 14:45:30 2009 > @@ -7,3 +7,14 @@ > 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; > +} > > Added: cfe/trunk/test/Sema/nested-redef.c > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/nested-redef.c?rev=61940&view=auto > > ============================================================================== > --- cfe/trunk/test/Sema/nested-redef.c (added) > +++ cfe/trunk/test/Sema/nested-redef.c Thu Jan 8 14:45:30 2009 > @@ -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; > +} > + > + > > Modified: cfe/trunk/test/SemaCXX/anonymous-union.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/anonymous-union.cpp?rev=61940&r1=61939&r2=61940&view=diff > > ============================================================================== > --- cfe/trunk/test/SemaCXX/anonymous-union.cpp (original) > +++ cfe/trunk/test/SemaCXX/anonymous-union.cpp Thu Jan 8 14:45:30 2009 > @@ -66,7 +66,7 @@ > 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}} > }; > > > Modified: cfe/trunk/test/SemaCXX/class.cpp > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/class.cpp?rev=61940&r1=61939&r2=61940&view=diff > > ============================================================================== > --- cfe/trunk/test/SemaCXX/class.cpp (original) > +++ cfe/trunk/test/SemaCXX/class.cpp Thu Jan 8 14:45:30 2009 > @@ -53,7 +53,7 @@ > > 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 @@ > 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'}} > +}; > > Modified: cfe/trunk/test/SemaObjC/duplicate-ivar-check.m > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjC/duplicate-ivar-check.m?rev=61940&r1=61939&r2=61940&view=diff > > ============================================================================== > --- cfe/trunk/test/SemaObjC/duplicate-ivar-check.m (original) > +++ cfe/trunk/test/SemaObjC/duplicate-ivar-check.m Thu Jan 8 14:45:30 2009 > @@ -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 > > Added: cfe/trunk/test/SemaObjC/interface-scope.m > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjC/interface-scope.m?rev=61940&view=auto > > ============================================================================== > --- cfe/trunk/test/SemaObjC/interface-scope.m (added) > +++ cfe/trunk/test/SemaObjC/interface-scope.m Thu Jan 8 14:45:30 2009 > @@ -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 > > Modified: cfe/trunk/test/SemaObjC/ivar-sem-check-1.m > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjC/ivar-sem-check-1.m?rev=61940&r1=61939&r2=61940&view=diff > > ============================================================================== > --- cfe/trunk/test/SemaObjC/ivar-sem-check-1.m (original) > +++ cfe/trunk/test/SemaObjC/ivar-sem-check-1.m Thu Jan 8 14:45:30 2009 > @@ -12,7 +12,7 @@ > 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}} > } > > > _______________________________________________ > cfe-commits mailing list > [email protected] > http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits > _______________________________________________ cfe-commits mailing list [email protected] http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits
