Factor out common logic from Spanned implementations

To compile the common code just once, rather than per distinct type T.

This also fixes a bug in the cfg(procmacro2_semver_exempt) case that
made Spanned::span always return call_site.
diff --git a/src/spanned.rs b/src/spanned.rs
index 767a6a7..a6f9aea 100644
--- a/src/spanned.rs
+++ b/src/spanned.rs
@@ -110,47 +110,51 @@
     impl<T: ToTokens> Sealed for T {}
 }
 
-// FIXME: This shouldn't be required, since optimally
-// spans should never be invalid. This can probably be removed when
-// https://github.com/rust-lang/rust/issues/43081 is resolved.
-fn check_invalid_span(span: Span) -> Option<Span> {
-    let debug = format!("{:?}", span);
-    if debug.ends_with("bytes(0..0)") {
-        None
-    } else {
-        Some(span)
-    }
-}
-
 impl<T> Spanned for T
 where
     T: ToTokens,
 {
-    #[cfg(procmacro2_semver_exempt)]
     fn span(&self) -> Span {
-        let mut tokens = TokenStream::new();
-        self.to_tokens(&mut tokens);
-        tokens
-            .into_iter()
-            .fold(None::<Span>, |span, tt| {
-                check_invalid_span(tt.span()).map_or(span, |new_span| {
-                    span.map(|span| span.join(new_span).unwrap_or(span))
-                })
-            })
-            .unwrap_or(Span::call_site())
+        join_spans(self.into_token_stream())
+    }
+}
+
+fn join_spans(tokens: TokenStream) -> Span {
+    let mut iter = tokens
+        .into_iter()
+        .filter_map(|tt| {
+            // FIXME: This shouldn't be required, since optimally spans should
+            // never be invalid. This filter_map can probably be removed when
+            // https://github.com/rust-lang/rust/issues/43081 is resolved.
+            let span = tt.span();
+            let debug = format!("{:?}", span);
+            if debug.ends_with("bytes(0..0)") {
+                None
+            } else {
+                Some(span)
+            }
+        });
+
+    let mut joined = match iter.next() {
+        Some(span) => span,
+        None => return Span::call_site(),
+    };
+
+    #[cfg(procmacro2_semver_exempt)]
+    {
+        for next in iter {
+            if let Some(span) = joined.join(next) {
+                joined = span;
+            }
+        }
     }
 
     #[cfg(not(procmacro2_semver_exempt))]
-    fn span(&self) -> Span {
-        let mut tokens = TokenStream::new();
-        self.to_tokens(&mut tokens);
-
+    {
         // We can't join spans without procmacro2_semver_exempt so just grab the
         // first one.
-        tokens
-            .into_iter()
-            .next()
-            .and_then(|tt| check_invalid_span(tt.span()))
-            .unwrap_or(Span::call_site())
+        joined = joined;
     }
+
+    joined
 }