From: Douglas Gregor Date: Mon, 12 Jan 2009 18:45:55 +0000 (+0000) Subject: Properly set the scope of non-fields declared within a struct, union, X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=1a0d31a3d7f14ddc6370ba912c778aece6c12cf0;p=clang Properly set the scope of non-fields declared within a struct, union, or enum to be outside that struct, union, or enum. Fixes several regressions: PR clang/3305 PR clang/3312 There is still some work to do in Objective-C++, but this requires that each of the Objective-C entities (interfaces, implementations, etc.) to be introduced into the context stack with PushDeclContext/PopDeclContext. This will be a separate fix, later. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@62091 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Parse/ParseObjc.cpp b/lib/Parse/ParseObjc.cpp index 90a1494966..f406eabf56 100644 --- a/lib/Parse/ParseObjc.cpp +++ b/lib/Parse/ParseObjc.cpp @@ -848,7 +848,7 @@ void Parser::ParseObjCClassInstanceVariables(DeclTy *interfaceDecl, llvm::SmallVector AllIvarDecls; llvm::SmallVector FieldDeclarators; - ParseScope ClassScope(this, Scope::DeclScope); + ParseScope ClassScope(this, Scope::DeclScope|Scope::ClassScope); SourceLocation LBraceLoc = ConsumeBrace(); // the "{" diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index f699e496cf..4db6f646b6 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -506,6 +506,8 @@ public: // we will need a better way to specify lookup criteria for things // like template specializations, explicit template instantiations, etc. + Scope *getNonFieldDeclScope(Scope *S); + /// More parsing and symbol table subroutines. Decl *LookupDecl(DeclarationName Name, unsigned NSI, Scope *S, const DeclContext *LookupCtx = 0, diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index a67049cf14..f3f0a08bee 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -251,6 +251,38 @@ MaybeConstructOverloadSet(ASTContext &Context, return *I; } +/// getNonFieldDeclScope - Retrieves the innermost scope, starting +/// from S, where a non-field would be declared. This routine copes +/// with the difference between C and C++ scoping rules in structs and +/// unions. For example, the following code is well-formed in C but +/// ill-formed in C++: +/// @code +/// struct S6 { +/// enum { BAR } e; +/// }; +/// +/// void test_S6() { +/// struct S6 a; +/// a.e = BAR; +/// } +/// @endcode +/// For the declaration of BAR, this routine will return a different +/// scope. The scope S will be the scope of the unnamed enumeration +/// within S6. In C++, this routine will return the scope associated +/// with S6, because the enumeration's scope is a transparent +/// context but structures can contain non-field names. In C, this +/// routine will return the translation unit scope, since the +/// enumeration's scope is a transparent context and structures cannot +/// contain non-field names. +Scope *Sema::getNonFieldDeclScope(Scope *S) { + while (((S->getFlags() & Scope::DeclScope) == 0) || + (S->getEntity() && + ((DeclContext *)S->getEntity())->isTransparentContext()) || + (S->isClassScope() && !getLangOptions().CPlusPlus)) + S = S->getParent(); + return S; +} + /// LookupDecl - Look up the inner-most declaration in the specified /// namespace. NamespaceNameOnly - during lookup only namespace names /// are considered as required in C++ [basic.lookup.udir] 3.4.6.p1 @@ -2999,7 +3031,9 @@ Sema::DeclTy *Sema::ActOnTag(Scope *S, unsigned TagType, TagKind TK, // Find the scope where we'll be declaring the tag. while (S->isClassScope() || (getLangOptions().CPlusPlus && S->isFunctionPrototypeScope()) || - ((S->getFlags() & Scope::DeclScope) == 0)) + ((S->getFlags() & Scope::DeclScope) == 0) || + (S->getEntity() && + ((DeclContext *)S->getEntity())->isTransparentContext())) S = S->getParent(); } @@ -3065,10 +3099,7 @@ CreateNewDecl: // If this has an identifier, add it to the scope stack. if (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(); + S = getNonFieldDeclScope(S); // Add it to the decl chain. if (LexicalContext != CurContext) { @@ -3509,8 +3540,7 @@ Sema::DeclTy *Sema::ActOnEnumConstant(Scope *S, DeclTy *theEnumDecl, // 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(); + S = getNonFieldDeclScope(S); // Verify that there isn't already something declared with this name in this // scope. diff --git a/test/Sema/type-spec-struct-union.c b/test/Sema/type-spec-struct-union.c index 38e57f7c1b..47de16be7a 100644 --- a/test/Sema/type-spec-struct-union.c +++ b/test/Sema/type-spec-struct-union.c @@ -35,3 +35,31 @@ int test_struct_scope_3(struct S4 * s4) { // expected-warning{{declaration of 's } void f(struct S5 { int y; } s5); // expected-warning{{declaration of 'struct S5' will not be visible outside of this function}} + +// PR clang/3312 +struct S6 { + enum { BAR } e; +}; + +void test_S6() { + struct S6 a; + a.e = BAR; +} + +// +typedef struct z_foo_s { + struct bar_baz *baz; +} z_foo; +typedef z_foo *z_foop; +struct bar_baz { + enum { + SQUAT, FLAG, DICT4, DICT3, DICT2, DICT1, DICT0, HOP, CHECK4, CHECK3, CHECK2, CHECK1, DONE, BAD + } mode; + int nowrap; +}; +int +wizbiz_quxPoof(z) + z_foop z; +{ + z->baz->mode = z->baz->nowrap ? HOP : SQUAT; +} diff --git a/test/SemaObjC/interface-scope-2.m b/test/SemaObjC/interface-scope-2.m new file mode 100644 index 0000000000..1256e7db1a --- /dev/null +++ b/test/SemaObjC/interface-scope-2.m @@ -0,0 +1,126 @@ +// RUN: clang -fsyntax-only -verify %s +// FIXME: must also compile as Objective-C++ + +// +typedef struct objc_selector *SEL; +typedef signed char BOOL; +typedef unsigned int NSUInteger; +typedef struct _NSZone NSZone; +@class NSInvocation, NSMethodSignature, NSCoder, NSString, NSEnumerator; +@protocol NSObject +- (BOOL)isEqual:(id)object; +- (BOOL)respondsToSelector:(SEL)aSelector; +@end +@protocol NSCopying +- (id)copyWithZone:(NSZone *)zone; +@end +@protocol NSMutableCopying +- (id)mutableCopyWithZone:(NSZone *)zone; +@end +@protocol NSCoding +- (void)encodeWithCoder:(NSCoder *)aCoder; +@end +@interface NSObject {} +@end +@class NSString, NSData; +typedef struct _NSPoint {} +NSRange; +@interface NSString : NSObject +- (NSUInteger)length; +@end +@interface NSMutableString : NSString +- (void)replaceCharactersInRange:(NSRange)range withString:(NSString *)aString; +@end +@class NSArray, NSDictionary, NSMapTable; +@interface NSResponder : NSObject {} +@end +@protocol NSAnimatablePropertyContainer +- (id)animator; +@end +extern NSString *NSAnimationTriggerOrderIn ; +@interface NSView : NSResponder { + struct __VFlags2 {} _vFlags2; +} +@end +@class NSAttributedString, NSEvent, NSFont, NSFormatter, NSImage, NSMenu, NSText, NSView; +@interface FooiagramView : NSView { +id _delegate; +} +@end +@class FooiagramView; +@interface _FooiagramViewReserved : NSObject { +@public + NSMutableString *_typeToSelectString; + struct _FooiagramViewFlags { + unsigned int delegateRespondsToPrintInfoForBarView : 1; + } _dvFlags; +} +@end +extern _FooiagramViewReserved *_FooiagramViewBarViewReserved(FooiagramView *BarView); +@interface FooiagramView (FooiagramViewPrivate) ++ (Class)_defaultBarToolManagerClass; +@end +@implementation FooiagramView +static NSMapTable *_defaultMenuForClass = 0; +- (void)setDelegate:(id)delegate { + if (_delegate != delegate) { + struct _FooiagramViewFlags *dvFlags = + &_FooiagramViewBarViewReserved(self)->_dvFlags; + if (_delegate != ((void *)0)) { + dvFlags->delegateRespondsToPrintInfoForBarView = [_delegate respondsToSelector:@selector(printInfoForBarView:)]; + } + } +} +@end + +// +@interface WizKing_MIKeep { +struct __LoreStuffNode *_historyStuff; +} +@end +typedef struct __LoreStuffNode {} LoreStuffNode; +@implementation WizKing_MIKeep +- init { + LoreStuffNode *node; + node = &(_historyStuff[1]); +} +@end + +// +typedef long unsigned int __darwin_size_t; +typedef __darwin_size_t size_t; +void *memset(void *, int, size_t); +@class NSString, NSURL, NSError; +@interface OingoWerdnaPeon : NSObject {} +@end typedef enum { +OingoPT_SmashOK, OingoPT_NoSuchFile, } +OingoWerdnaPeonIOMethod; +@interface OingoWerdnaPeonSmashDrivel : NSObject {} +@end +@interface OingoBoingoContraptionPeon : OingoWerdnaPeon { +struct _OingoBoingoContraptionPeonFlags {} +_nfttFlags; +} +@end +@implementation OingoBoingoContraptionPeon ++ (void)initialize {} +- (id)initWithSmashDrivel:(OingoWerdnaPeonSmashDrivel *)info { + if (self != ((void *)0)) { + (void)memset(&_nfttFlags, 0, sizeof(struct _OingoBoingoContraptionPeonFlags)); + } +} +@end + +@interface Blah { + struct X { + int x; + } value; +} +@end + +@implementation Blah +- (int)getValue { + struct X *xp = &value; + return xp->x; +} +@end