]> granicus.if.org Git - clang/commitdiff
When declaring an ObjC interface decl with a @compatibility_alias alias name, change...
authorArgyrios Kyrtzidis <akyrtzi@gmail.com>
Tue, 18 Jun 2013 21:26:33 +0000 (21:26 +0000)
committerArgyrios Kyrtzidis <akyrtzi@gmail.com>
Tue, 18 Jun 2013 21:26:33 +0000 (21:26 +0000)
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.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@184238 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Sema/SemaDeclObjC.cpp
test/PCH/objc_import.h
test/PCH/objc_import.m

index 9f10b7bb7ea91db99b1eb63ddd2b793bb32abf9b..526e479af08182d0658094c0ad65ba4f830f37dd 100644 (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);
index 8af87ab25c7d6377f05c8fb986548b0858807155..4646e16a2cdbfe2a1dfe86fdf3dfc2833185536c 100644 (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
index c7dd805b3e470ff652ba6ced056ba58b6fae96e4..724c8221848b4282501484ac07865a1f3dc24814 100644 (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];
+}