]> granicus.if.org Git - clang/commitdiff
[objc] If an interface has no initializer marked as designated and introduces at...
authorArgyrios Kyrtzidis <akyrtzi@gmail.com>
Thu, 5 Dec 2013 07:07:03 +0000 (07:07 +0000)
committerArgyrios Kyrtzidis <akyrtzi@gmail.com>
Thu, 5 Dec 2013 07:07:03 +0000 (07:07 +0000)
don't assume that it inherits the designated initializers from the super class.

If the assumption was wrong because a new initializer was a designated one that was not marked as such,
we will emit misleading warnings for subclasses of the interface.

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

include/clang/AST/DeclObjC.h
lib/AST/DeclObjC.cpp
test/SemaObjC/attr-designated-init.m

index d4515a272d9eab1876619a04dac44d115ff4b87d..9dcf4b9236661e14e1c3c7f88d2408230e4893f5 100644 (file)
@@ -678,6 +678,18 @@ class ObjCInterfaceDecl : public ObjCContainerDecl
     /// marked with the 'objc_designated_initializer' attribute.
     bool HasDesignatedInitializers : 1;
 
+    enum InheritedDesignatedInitializersState {
+      /// We didn't calculated whether the designated initializers should be
+      /// inherited or not.
+      IDI_Unknown = 0,
+      /// Designated initializers are inherited for the super class.
+      IDI_Inherited = 1,
+      /// The class does not inherit designated initializers.
+      IDI_NotInherited = 2
+    };
+    /// One of the \c InheritedDesignatedInitializersState enumeratos.
+    mutable unsigned InheritedDesignatedInitializers : 2;
+
     /// \brief The location of the superclass, if any.
     SourceLocation SuperClassLoc;
     
@@ -689,7 +701,8 @@ class ObjCInterfaceDecl : public ObjCContainerDecl
     DefinitionData() : Definition(), SuperClass(), CategoryList(), IvarList(), 
                        ExternallyCompleted(),
                        IvarListMissingImplementation(true),
-                       HasDesignatedInitializers() { }
+                       HasDesignatedInitializers(),
+                       InheritedDesignatedInitializers(IDI_Unknown) { }
   };
 
   ObjCInterfaceDecl(DeclContext *DC, SourceLocation atLoc, IdentifierInfo *Id,
@@ -1273,6 +1286,10 @@ public:
   friend class ASTReader;
   friend class ASTDeclReader;
   friend class ASTDeclWriter;
+
+private:
+  const ObjCInterfaceDecl *findInterfaceWithDesignatedInitializers() const;
+  bool inheritsDesignatedInitializers() const;
 };
 
 /// ObjCIvarDecl - Represents an ObjC instance variable. In general, ObjC
index 7fe73efc9ebcc500eb477a4c46babf407acf3aaf..eaf34c1de1af12fd8891c968d0c056885bd373e7 100644 (file)
@@ -380,21 +380,61 @@ void ObjCInterfaceDecl::mergeClassExtensionProtocolList(
   data().AllReferencedProtocols.set(ProtocolRefs.data(), ProtocolRefs.size(),C);
 }
 
-void ObjCInterfaceDecl::getDesignatedInitializers(
-    llvm::SmallVectorImpl<const ObjCMethodDecl *> &Methods) const {
-  assert(hasDefinition());
-  if (data().ExternallyCompleted)
-    LoadExternalDefinition();
-
+const ObjCInterfaceDecl *
+ObjCInterfaceDecl::findInterfaceWithDesignatedInitializers() const {
   const ObjCInterfaceDecl *IFace = this;
   while (IFace) {
-    if (IFace->data().HasDesignatedInitializers)
+    if (IFace->hasDesignatedInitializers())
+      return IFace;
+    if (!IFace->inheritsDesignatedInitializers())
       break;
     IFace = IFace->getSuperClass();
   }
+  return 0;
+}
 
+bool ObjCInterfaceDecl::inheritsDesignatedInitializers() const {
+  switch (data().InheritedDesignatedInitializers) {
+  case DefinitionData::IDI_Inherited:
+    return true;
+  case DefinitionData::IDI_NotInherited:
+    return false;
+  case DefinitionData::IDI_Unknown: {
+    bool isIntroducingInitializers = false;
+    for (instmeth_iterator I = instmeth_begin(),
+                           E = instmeth_end(); I != E; ++I) {
+      const ObjCMethodDecl *MD = *I;
+      if (MD->getMethodFamily() == OMF_init && !MD->isOverriding()) {
+        isIntroducingInitializers = true;
+        break;
+      }
+    }
+    // If the class introduced initializers we conservatively assume that we
+    // don't know if any of them is a designated initializer to avoid possible
+    // misleading warnings.
+    if (isIntroducingInitializers) {
+      data().InheritedDesignatedInitializers = DefinitionData::IDI_NotInherited;
+      return false;
+    } else {
+      data().InheritedDesignatedInitializers = DefinitionData::IDI_Inherited;
+      return true;
+    }
+  }
+  }
+
+  llvm_unreachable("unexpected InheritedDesignatedInitializers value");
+}
+
+void ObjCInterfaceDecl::getDesignatedInitializers(
+    llvm::SmallVectorImpl<const ObjCMethodDecl *> &Methods) const {
+  assert(hasDefinition());
+  if (data().ExternallyCompleted)
+    LoadExternalDefinition();
+
+  const ObjCInterfaceDecl *IFace= findInterfaceWithDesignatedInitializers();
   if (!IFace)
     return;
+
   for (instmeth_iterator I = IFace->instmeth_begin(),
                          E = IFace->instmeth_end(); I != E; ++I) {
     const ObjCMethodDecl *MD = *I;
@@ -409,13 +449,7 @@ bool ObjCInterfaceDecl::isDesignatedInitializer(Selector Sel,
   if (data().ExternallyCompleted)
     LoadExternalDefinition();
 
-  const ObjCInterfaceDecl *IFace = this;
-  while (IFace) {
-    if (IFace->data().HasDesignatedInitializers)
-      break;
-    IFace = IFace->getSuperClass();
-  }
-
+  const ObjCInterfaceDecl *IFace= findInterfaceWithDesignatedInitializers();
   if (!IFace)
     return false;
 
index 3d8bd1c3e5ecc51a335da4773fcd7b554b281a0d..dd908854a396cafe2a2fea7466728b9f8d81d617 100644 (file)
@@ -34,7 +34,7 @@ __attribute__((objc_root_class))
 
 __attribute__((objc_root_class))
 @interface B1
--(id)initB1 NS_DESIGNATED_INITIALIZER; // expected-note 4 {{method marked as designated initializer of the class here}}
+-(id)initB1 NS_DESIGNATED_INITIALIZER; // expected-note 5 {{method marked as designated initializer of the class here}}
 -(id)initB2;
 -(id)initB3 NS_DESIGNATED_INITIALIZER; // expected-note 3 {{method marked as designated initializer of the class here}}
 @end
@@ -177,3 +177,29 @@ __attribute__((objc_root_class))
   return [s initS1];
 }
 @end
+
+@interface SS4 : S4
+-(id)initB1;
+@end
+
+@implementation SS4
+-(id)initB1 { // expected-warning {{designated initializer missing a 'super' call to a designated initializer of the super class}}
+  return 0;
+}
+@end
+
+@interface S7 : B1
+-(id)initB1;
+-(id)initB3;
+-(id)initNewOne;
+@end
+
+@interface SS7 : S7
+-(id)initB1;
+@end
+
+@implementation SS7
+-(id)initB1 {
+  return 0;
+}
+@end