]> granicus.if.org Git - clang/commitdiff
InstrProf: Don't emit coverage for uninstantiated templates
authorJustin Bogner <mail@justinbogner.com>
Tue, 18 Nov 2014 00:34:46 +0000 (00:34 +0000)
committerJustin Bogner <mail@justinbogner.com>
Tue, 18 Nov 2014 00:34:46 +0000 (00:34 +0000)
We include unused functions and methods in -fcoverage-mapping so that
we can differentiate between uninstrumented and unused. This can cause
problems for uninstantiated templates though, since they may involve
an incomplete type that can't be mangled. This shows up in things like
libc++'s <unordered_map> and makes coverage unusable.

Avoid the issue by skipping uninstantiated methods of a templated
class.

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

lib/CodeGen/ModuleBuilder.cpp
test/CoverageMapping/classtemplate.cpp

index 6c60b4e62c1883e7fb71fb37757dd4124481b7f6..ee6f6f94c715816062568672bb316baac7dca520 100644 (file)
@@ -145,9 +145,11 @@ namespace {
       //   } A;
       DeferredInlineMethodDefinitions.push_back(D);
 
-      // Always provide some coverage mapping
-      // even for the methods that aren't emitted.
-      Builder->AddDeferredUnusedCoverageMapping(D);
+      // Provide some coverage mapping even for methods that aren't emitted.
+      // Don't do this for templated classes though, as they may not be
+      // instantiable.
+      if (!D->getParent()->getDescribedClassTemplate())
+        Builder->AddDeferredUnusedCoverageMapping(D);
     }
 
     /// HandleTagDeclDefinition - This callback is invoked each time a TagDecl
index e6938d625ada742f969cf29fc7b798565e3a3f2e..6062266fd47d063f1e4bf139cd93c29610e50ac7 100644 (file)
@@ -12,18 +12,38 @@ public:
   const static int BaseCount = 4;
   double bases[BaseCount];
 
-                                        // CHECK-CONSTRUCTOR: Test
+                                        // CHECK-CONSTRUCTOR: _ZN4TestIjEC
   Test() { }                            // CHECK-CONSTRUCTOR: File 0, [[@LINE]]:10 -> [[@LINE]]:13 = #0 (HasCodeBefore = 0)
-                                        // CHECK-GETTER: get
-  double get(TT position) const {       // CHECK-GETTER: File 0, [[@LINE]]:33 -> [[@LINE+2]]:4 = 0 (HasCodeBefore = 0)
+
+  // FIXME: It would be nice to emit no-coverage for get, but trying to do this
+  // runs afoul of cases like Test3::unmangleable below.
+                                        // FIXME-GETTER: _ZNK4TestIjE3get
+  double get(TT position) const {       // FIXME-GETTER: File 0, [[@LINE]]:33 -> [[@LINE+2]]:4 = 0 (HasCodeBefore = 0)
     return bases[position];
   }
-                                        // CHECK-SETTER: set
+                                        // CHECK-SETTER: _ZN4TestIjE3set
   void set(TT position, double value) { // CHECK-SETTER: File 0, [[@LINE]]:39 -> [[@LINE+2]]:4 = #0 (HasCodeBefore = 0)
     bases[position] = value;
   }
 };
 
+class Test2 {
+                                        // CHECK-CONSTRUCTOR: _ZN5Test2C
+  Test2() { }                           // CHECK-CONSTRUCTOR: File 0, [[@LINE]]:11 -> [[@LINE]]:14 = 0 (HasCodeBefore = 0)
+                                        // CHECK-GETTER: _ZNK5Test23get
+  double get(unsigned position) const { // CHECK-GETTER: File 0, [[@LINE]]:39 -> [[@LINE+2]]:4 = 0 (HasCodeBefore = 0)
+    return 0.0;
+  }
+};
+
+// Test3::unmangleable can't be mangled, since there isn't a complete type for
+// the __is_final type trait expression. This would cause errors if we try to
+// emit a no-coverage mapping for the method.
+template <class T, bool = __is_final(T)> class UninstantiatedClassWithTraits {};
+template <class T> class Test3 {
+  void unmangleable(UninstantiatedClassWithTraits<T> x) {}
+};
+
 int main() {
   Test<unsigned> t;
   t.set(Test<unsigned>::A, 5.5);