]> granicus.if.org Git - clang/commitdiff
Objective-C: Serialize "more than one decl" state of ObjCMethodList.
authorNico Weber <nicolasweber@gmx.de>
Sat, 27 Dec 2014 22:14:15 +0000 (22:14 +0000)
committerNico Weber <nicolasweber@gmx.de>
Sat, 27 Dec 2014 22:14:15 +0000 (22:14 +0000)
This fixes PR21587, what r221933 fixed for regular programs is now also
fixed for decls coming from PCH files.

Use another bit from the count/bits uint16_t for storing the "more than one
decl" bit.  This reduces the number of bits for the count from 14 to 13.
The selector with the most overloads in Cocoa.h has ~55 overloads, so 13 bits
should still be plenty.  Since this changes the meaning of a serialized bit
pattern, also increase clang::serialization::VERSION_MAJOR.

Storing the "more than one decl" state of only the first overload isn't quite
correct, but Sema::AreMultipleMethodsInGlobalPool() currently only looks at
the state of the first overload so it's good enough for now.

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

include/clang/Sema/ObjCMethodList.h
include/clang/Serialization/ASTBitCodes.h
lib/Serialization/ASTReader.cpp
lib/Serialization/ASTReaderInternals.h
lib/Serialization/ASTWriter.cpp
test/SemaObjC/attr-deprecated-pch.m [new file with mode: 0644]

index 6c759d922ae8503b8cb446a8fc019363680246bc..b618e38f88cd415731ca98db084365fa6e0b81f0 100644 (file)
@@ -23,6 +23,7 @@ class ObjCMethodDecl;
 /// \brief a linked list of methods with the same selector name but different
 /// signatures.
 struct ObjCMethodList {
+  // NOTE: If you add any members to this struct, make sure to serialize them.
   /// \brief If there is more than one decl with this signature.
   llvm::PointerIntPair<ObjCMethodDecl *, 1> MethodAndHasMoreThanOneDecl;
   /// \brief The next list object and 2 bits for extra info.
index d8629c2dde59d438d1b5896a75c64828489345bf..3874f3a64c1bbd084dbb682b69839a16233074ba 100644 (file)
@@ -35,7 +35,7 @@ namespace clang {
     /// Version 4 of AST files also requires that the version control branch and
     /// revision match exactly, since there is no backward compatibility of
     /// AST files at this time.
-    const unsigned VERSION_MAJOR = 5;
+    const unsigned VERSION_MAJOR = 6;
 
     /// \brief AST file minor version number supported by this version of
     /// Clang.
index b3bac25a0767b5a8472d598faae5222305fffe6b..7d6565aac38f481704fc8114c2f127a44c27fe93 100644 (file)
@@ -650,14 +650,14 @@ ASTSelectorLookupTrait::ReadData(Selector, const unsigned char* d,
 
   Result.ID = Reader.getGlobalSelectorID(
       F, endian::readNext<uint32_t, little, unaligned>(d));
-  unsigned NumInstanceMethodsAndBits =
-      endian::readNext<uint16_t, little, unaligned>(d);
-  unsigned NumFactoryMethodsAndBits =
-      endian::readNext<uint16_t, little, unaligned>(d);
-  Result.InstanceBits = NumInstanceMethodsAndBits & 0x3;
-  Result.FactoryBits = NumFactoryMethodsAndBits & 0x3;
-  unsigned NumInstanceMethods = NumInstanceMethodsAndBits >> 2;
-  unsigned NumFactoryMethods = NumFactoryMethodsAndBits >> 2;
+  unsigned FullInstanceBits = endian::readNext<uint16_t, little, unaligned>(d);
+  unsigned FullFactoryBits = endian::readNext<uint16_t, little, unaligned>(d);
+  Result.InstanceBits = FullInstanceBits & 0x3;
+  Result.InstanceHasMoreThanOneDecl = (FullInstanceBits >> 2) & 0x1;
+  Result.FactoryBits = FullFactoryBits & 0x3;
+  Result.FactoryHasMoreThanOneDecl = (FullFactoryBits >> 2) & 0x1;
+  unsigned NumInstanceMethods = FullInstanceBits >> 3;
+  unsigned NumFactoryMethods = FullFactoryBits >> 3;
 
   // Load instance methods
   for (unsigned I = 0; I != NumInstanceMethods; ++I) {
@@ -7061,6 +7061,8 @@ namespace clang { namespace serialization {
     unsigned PriorGeneration;
     unsigned InstanceBits;
     unsigned FactoryBits;
+    bool InstanceHasMoreThanOneDecl;
+    bool FactoryHasMoreThanOneDecl;
     SmallVector<ObjCMethodDecl *, 4> InstanceMethods;
     SmallVector<ObjCMethodDecl *, 4> FactoryMethods;
 
@@ -7068,7 +7070,8 @@ namespace clang { namespace serialization {
     ReadMethodPoolVisitor(ASTReader &Reader, Selector Sel,
                           unsigned PriorGeneration)
         : Reader(Reader), Sel(Sel), PriorGeneration(PriorGeneration),
-          InstanceBits(0), FactoryBits(0) {}
+          InstanceBits(0), FactoryBits(0), InstanceHasMoreThanOneDecl(false),
+          FactoryHasMoreThanOneDecl(false) {}
 
     static bool visit(ModuleFile &M, void *UserData) {
       ReadMethodPoolVisitor *This
@@ -7103,6 +7106,8 @@ namespace clang { namespace serialization {
       This->FactoryMethods.append(Data.Factory.begin(), Data.Factory.end());
       This->InstanceBits = Data.InstanceBits;
       This->FactoryBits = Data.FactoryBits;
+      This->InstanceHasMoreThanOneDecl = Data.InstanceHasMoreThanOneDecl;
+      This->FactoryHasMoreThanOneDecl = Data.FactoryHasMoreThanOneDecl;
       return true;
     }
     
@@ -7118,6 +7123,10 @@ namespace clang { namespace serialization {
 
     unsigned getInstanceBits() const { return InstanceBits; }
     unsigned getFactoryBits() const { return FactoryBits; }
+    bool instanceHasMoreThanOneDecl() const {
+      return InstanceHasMoreThanOneDecl;
+    }
+    bool factoryHasMoreThanOneDecl() const { return FactoryHasMoreThanOneDecl; }
   };
 } } // end namespace clang::serialization
 
@@ -7156,7 +7165,9 @@ void ASTReader::ReadMethodPool(Selector Sel) {
   addMethodsToPool(S, Visitor.getInstanceMethods(), Pos->second.first);
   addMethodsToPool(S, Visitor.getFactoryMethods(), Pos->second.second);
   Pos->second.first.setBits(Visitor.getInstanceBits());
+  Pos->second.first.setHasMoreThanOneDecl(Visitor.instanceHasMoreThanOneDecl());
   Pos->second.second.setBits(Visitor.getFactoryBits());
+  Pos->second.second.setHasMoreThanOneDecl(Visitor.factoryHasMoreThanOneDecl());
 }
 
 void ASTReader::ReadKnownNamespaces(
index 2f0d37e77c9945c65dc4681bdf8d053e0f9b02d5..d1b032b27ac22208dabfddc9987631ac2fa763bd 100644 (file)
@@ -156,6 +156,8 @@ public:
     SelectorID ID;
     unsigned InstanceBits;
     unsigned FactoryBits;
+    bool InstanceHasMoreThanOneDecl;
+    bool FactoryHasMoreThanOneDecl;
     SmallVector<ObjCMethodDecl *, 2> Instance;
     SmallVector<ObjCMethodDecl *, 2> Factory;
   };
index c5d5b984cd39170108a9baa5e98c0707a63b2c37..6c60d45503de88f56b8d7a24988c8646a78c3a2d 100644 (file)
@@ -2940,13 +2940,20 @@ public:
 
     unsigned InstanceBits = Methods.Instance.getBits();
     assert(InstanceBits < 4);
-    unsigned NumInstanceMethodsAndBits =
-        (NumInstanceMethods << 2) | InstanceBits;
+    unsigned InstanceHasMoreThanOneDeclBit =
+        Methods.Instance.hasMoreThanOneDecl();
+    unsigned FullInstanceBits = (NumInstanceMethods << 3) |
+                                (InstanceHasMoreThanOneDeclBit << 2) |
+                                InstanceBits;
     unsigned FactoryBits = Methods.Factory.getBits();
     assert(FactoryBits < 4);
-    unsigned NumFactoryMethodsAndBits = (NumFactoryMethods << 2) | FactoryBits;
-    LE.write<uint16_t>(NumInstanceMethodsAndBits);
-    LE.write<uint16_t>(NumFactoryMethodsAndBits);
+    unsigned FactoryHasMoreThanOneDeclBit =
+        Methods.Factory.hasMoreThanOneDecl();
+    unsigned FullFactoryBits = (NumFactoryMethods << 3) |
+                               (FactoryHasMoreThanOneDeclBit << 2) |
+                               FactoryBits;
+    LE.write<uint16_t>(FullInstanceBits);
+    LE.write<uint16_t>(FullFactoryBits);
     for (const ObjCMethodList *Method = &Methods.Instance; Method;
          Method = Method->getNext())
       if (Method->getMethod())
diff --git a/test/SemaObjC/attr-deprecated-pch.m b/test/SemaObjC/attr-deprecated-pch.m
new file mode 100644 (file)
index 0000000..2b48aea
--- /dev/null
@@ -0,0 +1,23 @@
+// RUN: %clang_cc1 -fsyntax-only -DBOTH -verify %s
+// If the decls come from a pch, the behavior shouldn't change:
+// RUN: %clang_cc1 -x objective-c-header %s -emit-pch -o %t
+// RUN: %clang_cc1 -DUSES -include-pch %t -fsyntax-only -verify %s
+// expected-no-diagnostics
+
+// The slightly strange ifdefs are so that the command that builds the gch file
+// doesn't need any -D switches, for these would get embedded in the gch.
+
+#ifndef USES
+@interface Interface1
+- (void)partiallyUnavailableMethod;
+@end
+@interface Interface2
+- (void)partiallyUnavailableMethod __attribute__((unavailable));
+@end
+#endif
+
+#if defined(USES) || defined(BOTH)
+void f(id a) {
+  [a partiallyUnavailableMethod];  // no warning, `a` could be an Interface1.
+}
+#endif