When declaring an ObjC interface decl with a @compatibility_alias alias name, change the class name to the "real" one.

If we have something like

  @class NewImage;
  @compatibility_alias OldImage NewImage;
  @class OldImage;

the lookup for 'OldImage' will return the 'NewImage' decl ("@class NewImage").
In such a case, when creating the decl for "@class OldImage" use the real declaration name ("NewImage"),
instead of the alias one ("OldImage"), otherwise we will break IdentifierResolver and redecls-chain invariants.

Fixes crash of rdar://14112291.

llvm-svn: 184238
This commit is contained in:
Argyrios Kyrtzidis 2013-06-18 21:26:33 +00:00
parent a721731fdd
commit dd7106375c
3 changed files with 62 additions and 1 deletions

View File

@ -459,6 +459,23 @@ ActOnStartClassInterface(SourceLocation AtInterfaceLoc,
// Create a declaration to describe this @interface.
ObjCInterfaceDecl* PrevIDecl = dyn_cast_or_null<ObjCInterfaceDecl>(PrevDecl);
if (PrevIDecl && PrevIDecl->getIdentifier() != ClassName) {
// A previous decl with a different name is because of
// @compatibility_alias, for example:
// \code
// @class NewImage;
// @compatibility_alias OldImage NewImage;
// \endcode
// A lookup for 'OldImage' will return the 'NewImage' decl.
//
// In such a case use the real declaration name, instead of the alias one,
// otherwise we will break IdentifierResolver and redecls-chain invariants.
// FIXME: If necessary, add a bit to indicate that this ObjCInterfaceDecl
// has been aliased.
ClassName = PrevIDecl->getIdentifier();
}
ObjCInterfaceDecl *IDecl
= ObjCInterfaceDecl::Create(Context, CurContext, AtInterfaceLoc, ClassName,
PrevIDecl, ClassLoc);
@ -1938,9 +1955,27 @@ Sema::ActOnForwardClassDeclaration(SourceLocation AtClassLoc,
// Create a declaration to describe this forward declaration.
ObjCInterfaceDecl *PrevIDecl
= dyn_cast_or_null<ObjCInterfaceDecl>(PrevDecl);
IdentifierInfo *ClassName = IdentList[i];
if (PrevIDecl && PrevIDecl->getIdentifier() != ClassName) {
// A previous decl with a different name is because of
// @compatibility_alias, for example:
// \code
// @class NewImage;
// @compatibility_alias OldImage NewImage;
// \endcode
// A lookup for 'OldImage' will return the 'NewImage' decl.
//
// In such a case use the real declaration name, instead of the alias one,
// otherwise we will break IdentifierResolver and redecls-chain invariants.
// FIXME: If necessary, add a bit to indicate that this ObjCInterfaceDecl
// has been aliased.
ClassName = PrevIDecl->getIdentifier();
}
ObjCInterfaceDecl *IDecl
= ObjCInterfaceDecl::Create(Context, CurContext, AtClassLoc,
IdentList[i], PrevIDecl, IdentLocs[i]);
ClassName, PrevIDecl, IdentLocs[i]);
IDecl->setAtEndRange(IdentLocs[i]);
PushOnScopeChains(IDecl, TUScope);

View File

@ -5,3 +5,14 @@
- (void)instMethod;
@end
@class NewID1;
@compatibility_alias OldID1 NewID1;
@class OldID1;
@class OldID1;
@class NewID2;
@compatibility_alias OldID2 NewID2;
@class OldID2;
@interface OldID2
-(void)meth;
@end

View File

@ -15,3 +15,18 @@ void func() {
xx = [TestPCH alloc];
[xx instMethod];
}
// rdar://14112291
@class NewID1;
void foo1(NewID1 *p);
void bar1(OldID1 *p) {
foo1(p);
}
@class NewID2;
void foo2(NewID2 *p) {
[p meth];
}
void bar2(OldID2 *p) {
foo2(p);
[p meth];
}