about summary refs log tree commit diff
diff options
context:
space:
mode:
authorYuki Okushi <jtitor@2k36.org>2021-04-28 16:59:06 +0900
committerGitHub <noreply@github.com>2021-04-28 16:59:06 +0900
commit3f89ca1a32b666ca5733850ef26af26d9dc27d2e (patch)
tree9217a1ff06a11005167bf77eea3c0425d86c7a45
parent537544b1061467ee4b74ef7f552fab3d513e5caf (diff)
parent41667e853489c54b6e7960871aaa124ce0a5437b (diff)
downloadrust-3f89ca1a32b666ca5733850ef26af26d9dc27d2e.tar.gz
rust-3f89ca1a32b666ca5733850ef26af26d9dc27d2e.zip
Rollup merge of #84529 - richkadel:issue-84180, r=tmandry
Improve coverage spans for chained function calls

Fixes: #84180

For chained function calls separated by the `?` try operator, the
function call following the try operator produced a MIR `Call` span that
matched the span of the first call. The `?` try operator started a new
span, so the second call got no span.

It turns out the MIR `Call` terminator has a `func` `Operand`
for the `Constant` representing the function name, and the function
name's Span can be used to reset the starting position of the span.

r? `@tmandry`
cc: `@wesleywiser`
-rw-r--r--compiler/rustc_mir/src/transform/coverage/spans.rs12
-rw-r--r--src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.try_error_result.txt89
-rw-r--r--src/test/run-make-fulldeps/coverage/try_error_result.rs84
3 files changed, 182 insertions, 3 deletions
diff --git a/compiler/rustc_mir/src/transform/coverage/spans.rs b/compiler/rustc_mir/src/transform/coverage/spans.rs
index 249f5e835cd..2041109eb38 100644
--- a/compiler/rustc_mir/src/transform/coverage/spans.rs
+++ b/compiler/rustc_mir/src/transform/coverage/spans.rs
@@ -717,11 +717,21 @@ pub(super) fn filtered_terminator_span(
         | TerminatorKind::FalseEdge { .. }
         | TerminatorKind::Goto { .. } => None,
 
+        // Call `func` operand can have a more specific span when part of a chain of calls
+        | TerminatorKind::Call { ref func, .. } => {
+            let mut span = terminator.source_info.span;
+            if let mir::Operand::Constant(box constant) = func {
+                if constant.span.lo() > span.lo() {
+                    span = span.with_lo(constant.span.lo());
+                }
+            }
+            Some(function_source_span(span, body_span))
+        }
+
         // Retain spans from all other terminators
         TerminatorKind::Resume
         | TerminatorKind::Abort
         | TerminatorKind::Return
-        | TerminatorKind::Call { .. }
         | TerminatorKind::Yield { .. }
         | TerminatorKind::GeneratorDrop
         | TerminatorKind::FalseUnwind { .. }
diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.try_error_result.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.try_error_result.txt
index c9ebffde039..9fca52451ed 100644
--- a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.try_error_result.txt
+++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.try_error_result.txt
@@ -9,7 +9,7 @@
     9|       |    }
    10|      6|}
    11|       |
-   12|      1|fn main() -> Result<(),()> {
+   12|      1|fn test1() -> Result<(),()> {
    13|      1|    let mut
    14|      1|        countdown = 10
    15|       |    ;
@@ -35,4 +35,91 @@
    34|       |    }
    35|      0|    Ok(())
    36|      1|}
+   37|       |
+   38|       |struct Thing1;
+   39|       |impl Thing1 {
+   40|     18|    fn get_thing_2(&self, return_error: bool) -> Result<Thing2,()> {
+   41|     18|        if return_error {
+   42|      1|            Err(())
+   43|       |        } else {
+   44|     17|            Ok(Thing2{})
+   45|       |        }
+   46|     18|    }
+   47|       |}
+   48|       |
+   49|       |struct Thing2;
+   50|       |impl Thing2 {
+   51|     17|    fn call(&self, return_error: bool) -> Result<u32,()> {
+   52|     17|        if return_error {
+   53|      2|            Err(())
+   54|       |        } else {
+   55|     15|            Ok(57)
+   56|       |        }
+   57|     17|    }
+   58|       |}
+   59|       |
+   60|      1|fn test2() -> Result<(),()> {
+   61|      1|    let thing1 = Thing1{};
+   62|      1|    let mut
+   63|      1|        countdown = 10
+   64|       |    ;
+   65|       |    for
+   66|      6|        _
+   67|       |    in
+   68|      6|        0..10
+   69|       |    {
+   70|      6|        countdown
+   71|      6|            -= 1
+   72|      6|        ;
+   73|      6|        if
+   74|      6|            countdown < 5
+   75|       |        {
+   76|      1|            thing1.get_thing_2(/*err=*/ false)?.call(/*err=*/ true).expect_err("call should fail");
+                                                            ^0
+   77|      1|            thing1
+   78|      1|                .
+   79|      1|                get_thing_2(/*return_error=*/ false)
+   80|      0|                ?
+   81|       |                .
+   82|      1|                call(/*return_error=*/ true)
+   83|      1|                .
+   84|      1|                expect_err(
+   85|      1|                    "call should fail"
+   86|      1|                );
+   87|      1|            let val = thing1.get_thing_2(/*return_error=*/ true)?.call(/*return_error=*/ true)?;
+                              ^0                                                ^0                          ^0
+   88|      0|            assert_eq!(val, 57);
+   89|      0|            let val = thing1.get_thing_2(/*return_error=*/ true)?.call(/*return_error=*/ false)?;
+   90|      0|            assert_eq!(val, 57);
+   91|       |        }
+   92|       |        else
+   93|       |        {
+   94|      5|            let val = thing1.get_thing_2(/*return_error=*/ false)?.call(/*return_error=*/ false)?;
+                                                                               ^0                             ^0
+   95|      5|            assert_eq!(val, 57);
+   96|      5|            let val = thing1
+   97|      5|                .get_thing_2(/*return_error=*/ false)?
+                                                                   ^0
+   98|      5|                .call(/*return_error=*/ false)?;
+                                                            ^0
+   99|      5|            assert_eq!(val, 57);
+  100|      5|            let val = thing1
+  101|      5|                .get_thing_2(/*return_error=*/ false)
+  102|      0|                ?
+  103|      5|                .call(/*return_error=*/ false)
+  104|      0|                ?
+  105|       |                ;
+  106|      5|            assert_eq!(val, 57);
+  107|       |        }
+  108|       |    }
+  109|      0|    Ok(())
+  110|      1|}
+  111|       |
+  112|      1|fn main() -> Result<(),()> {
+  113|      1|    test1().expect_err("test1 should fail");
+  114|      1|    test2()
+  115|      1|    ?
+  116|       |    ;
+  117|      0|    Ok(())
+  118|      1|}
 
diff --git a/src/test/run-make-fulldeps/coverage/try_error_result.rs b/src/test/run-make-fulldeps/coverage/try_error_result.rs
index 13c455172dd..cd0acf72302 100644
--- a/src/test/run-make-fulldeps/coverage/try_error_result.rs
+++ b/src/test/run-make-fulldeps/coverage/try_error_result.rs
@@ -9,7 +9,7 @@ fn call(return_error: bool) -> Result<(),()> {
     }
 }
 
-fn main() -> Result<(),()> {
+fn test1() -> Result<(),()> {
     let mut
         countdown = 10
     ;
@@ -34,3 +34,85 @@ fn main() -> Result<(),()> {
     }
     Ok(())
 }
+
+struct Thing1;
+impl Thing1 {
+    fn get_thing_2(&self, return_error: bool) -> Result<Thing2,()> {
+        if return_error {
+            Err(())
+        } else {
+            Ok(Thing2{})
+        }
+    }
+}
+
+struct Thing2;
+impl Thing2 {
+    fn call(&self, return_error: bool) -> Result<u32,()> {
+        if return_error {
+            Err(())
+        } else {
+            Ok(57)
+        }
+    }
+}
+
+fn test2() -> Result<(),()> {
+    let thing1 = Thing1{};
+    let mut
+        countdown = 10
+    ;
+    for
+        _
+    in
+        0..10
+    {
+        countdown
+            -= 1
+        ;
+        if
+            countdown < 5
+        {
+            thing1.get_thing_2(/*err=*/ false)?.call(/*err=*/ true).expect_err("call should fail");
+            thing1
+                .
+                get_thing_2(/*return_error=*/ false)
+                ?
+                .
+                call(/*return_error=*/ true)
+                .
+                expect_err(
+                    "call should fail"
+                );
+            let val = thing1.get_thing_2(/*return_error=*/ true)?.call(/*return_error=*/ true)?;
+            assert_eq!(val, 57);
+            let val = thing1.get_thing_2(/*return_error=*/ true)?.call(/*return_error=*/ false)?;
+            assert_eq!(val, 57);
+        }
+        else
+        {
+            let val = thing1.get_thing_2(/*return_error=*/ false)?.call(/*return_error=*/ false)?;
+            assert_eq!(val, 57);
+            let val = thing1
+                .get_thing_2(/*return_error=*/ false)?
+                .call(/*return_error=*/ false)?;
+            assert_eq!(val, 57);
+            let val = thing1
+                .get_thing_2(/*return_error=*/ false)
+                ?
+                .call(/*return_error=*/ false)
+                ?
+                ;
+            assert_eq!(val, 57);
+        }
+    }
+    Ok(())
+}
+
+fn main() -> Result<(),()> {
+    test1().expect_err("test1 should fail");
+    test2()
+    ?
+    ;
+    Ok(())
+}