From dd7106375c2c7de682bf2997d2ef7bb55113219f Mon Sep 17 00:00:00 2001 From: Argyrios Kyrtzidis Date: Tue, 18 Jun 2013 21:26:33 +0000 Subject: [PATCH] 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 --- clang/lib/Sema/SemaDeclObjC.cpp | 37 ++++++++++++++++++++++++++++++++- clang/test/PCH/objc_import.h | 11 ++++++++++ clang/test/PCH/objc_import.m | 15 +++++++++++++ 3 files changed, 62 insertions(+), 1 deletion(-) diff --git a/clang/lib/Sema/SemaDeclObjC.cpp b/clang/lib/Sema/SemaDeclObjC.cpp index 9f10b7bb7ea9..526e479af081 100644 --- a/clang/lib/Sema/SemaDeclObjC.cpp +++ b/clang/lib/Sema/SemaDeclObjC.cpp @@ -459,6 +459,23 @@ ActOnStartClassInterface(SourceLocation AtInterfaceLoc, // Create a declaration to describe this @interface. ObjCInterfaceDecl* PrevIDecl = dyn_cast_or_null(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(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); diff --git a/clang/test/PCH/objc_import.h b/clang/test/PCH/objc_import.h index 8af87ab25c7d..4646e16a2cdb 100644 --- a/clang/test/PCH/objc_import.h +++ b/clang/test/PCH/objc_import.h @@ -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 diff --git a/clang/test/PCH/objc_import.m b/clang/test/PCH/objc_import.m index c7dd805b3e47..724c8221848b 100644 --- a/clang/test/PCH/objc_import.m +++ b/clang/test/PCH/objc_import.m @@ -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]; +}