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.

llvm-svn: 222204

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

index 6c60b4e..ee6f6f9 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 e6938d6..6062266 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);