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: 

  <rdar://problem/6487662>
  <rdar://problem/6487669>
  <rdar://problem/6487684>
  <rdar://problem/6487702>
  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.

llvm-svn: 62091
This commit is contained in:
Douglas Gregor 2009-01-12 18:45:55 +00:00
parent 5daa1abf25
commit 45a33ecce1
5 changed files with 194 additions and 8 deletions

View File

@ -848,7 +848,7 @@ void Parser::ParseObjCClassInstanceVariables(DeclTy *interfaceDecl,
llvm::SmallVector<DeclTy*, 32> AllIvarDecls;
llvm::SmallVector<FieldDeclarator, 8> FieldDeclarators;
ParseScope ClassScope(this, Scope::DeclScope);
ParseScope ClassScope(this, Scope::DeclScope|Scope::ClassScope);
SourceLocation LBraceLoc = ConsumeBrace(); // the "{"

View File

@ -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,

View File

@ -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.

View File

@ -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;
}
// <rdar://problem/6487669>
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;
}

View File

@ -0,0 +1,126 @@
// RUN: clang -fsyntax-only -verify %s
// FIXME: must also compile as Objective-C++
// <rdar://problem/6487662>
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 <NSObject> {}
@end
@class NSString, NSData;
typedef struct _NSPoint {}
NSRange;
@interface NSString : NSObject <NSCopying, NSMutableCopying, NSCoding>
- (NSUInteger)length;
@end
@interface NSMutableString : NSString
- (void)replaceCharactersInRange:(NSRange)range withString:(NSString *)aString;
@end
@class NSArray, NSDictionary, NSMapTable;
@interface NSResponder : NSObject <NSCoding> {}
@end
@protocol NSAnimatablePropertyContainer
- (id)animator;
@end
extern NSString *NSAnimationTriggerOrderIn ;
@interface NSView : NSResponder <NSAnimatablePropertyContainer> {
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
// <rdar://problem/6487684>
@interface WizKing_MIKeep {
struct __LoreStuffNode *_historyStuff;
}
@end
typedef struct __LoreStuffNode {} LoreStuffNode;
@implementation WizKing_MIKeep
- init {
LoreStuffNode *node;
node = &(_historyStuff[1]);
}
@end
// <rdar://problem/6487702>
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 <NSCopying> {}
@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