Index: src/wp-includes/class-wp-comment-query.php
===================================================================
--- src/wp-includes/class-wp-comment-query.php	(revision 34267)
+++ src/wp-includes/class-wp-comment-query.php	(working copy)
@@ -71,6 +71,35 @@
 	public $comments;
 
 	/**
+	 * The amount of comments for the current query.
+	 *
+	 * @since 4.4.0
+	 * @access public
+	 * @var int
+	 */
+	public $comment_count = 0;
+
+	/**
+	 * The amount of found comments for the current query.
+	 *
+	 * If limit clause was not used, equals $comment_count.
+	 *
+	 * @since 4.4.0
+	 * @access public
+	 * @var int
+	 */
+	public $found_comments = 0;
+
+	/**
+	 * The amount of pages.
+	 *
+	 * @since 4.4.0
+	 * @access public
+	 * @var int
+	 */
+	public $max_num_pages = 0;
+
+	/**
 	 * Make private/protected methods readable for backwards compatibility.
 	 *
 	 * @since 4.0.0
@@ -197,6 +226,7 @@
 			'user_id' => '',
 			'search' => '',
 			'count' => false,
+			'no_found_rows' => false,
 			'meta_key' => '',
 			'meta_value' => '',
 			'meta_query' => '',
@@ -208,6 +238,12 @@
 		}
 	}
 
+	public function init() {
+		$this->comment_count = 0;
+		$this->found_comments = 0;
+		$this->max_num_pages = 0;
+	}
+
 	/**
 	 * Parse arguments passed to the comment query with default query parameters.
 	 *
@@ -222,6 +258,7 @@
 			$query = $this->query_vars;
 		}
 
+		$this->init();
 		$this->query_vars = wp_parse_args( $query, $this->query_var_defaults );
 		do_action_ref_array( 'parse_comment_query', array( &$this ) );
 	}
@@ -281,6 +318,19 @@
 			$meta_query_clauses = $this->meta_query->get_sql( 'comment', $wpdb->comments, 'comment_ID', $this );
 		}
 
+		$number = absint( $this->query_vars['number'] );
+		$offset = absint( $this->query_vars['offset'] );
+
+		if ( ! empty( $number ) ) {
+			if ( $offset ) {
+				$limits = 'LIMIT ' . $offset . ',' . $number;
+			} else {
+				$limits = 'LIMIT ' . $number;
+			}
+		} else {
+			$limits = '';
+		}
+
 		// $args can include anything. Only use the args defined in the query_var_defaults to compute the key.
 		$key = md5( serialize( wp_array_slice_assoc( $this->query_vars, array_keys( $this->query_var_defaults ) ) ) );
 		$last_changed = wp_cache_get( 'last_changed', 'comment' );
@@ -292,6 +342,8 @@
 
 		if ( $cache = wp_cache_get( $cache_key, 'comment' ) ) {
 			$this->comments = $cache;
+			$this->comment_count = count( $this->comments );
+			$this->set_found_comments( $limits );
 			return $this->comments;
 		}
 
@@ -452,19 +504,6 @@
 			$orderby = "$wpdb->comments.comment_date_gmt $order";
 		}
 
-		$number = absint( $this->query_vars['number'] );
-		$offset = absint( $this->query_vars['offset'] );
-
-		if ( ! empty( $number ) ) {
-			if ( $offset ) {
-				$limits = 'LIMIT ' . $offset . ',' . $number;
-			} else {
-				$limits = 'LIMIT ' . $number;
-			}
-		} else {
-			$limits = '';
-		}
-
 		if ( $this->query_vars['count'] ) {
 			$fields = 'COUNT(*)';
 		} else {
@@ -671,8 +710,19 @@
 			$orderby = "ORDER BY $orderby";
 		}
 
-		$this->request = "SELECT $fields FROM $wpdb->comments $join $where $groupby $orderby $limits";
+		if ( isset( $this->query_vars['no_found_rows'] ) ) {
+			$this->query_vars['no_found_rows'] = (bool) $this->query_vars['no_found_rows'];
+		} else {
+			$this->query_vars['no_found_rows'] = false;
+		}
 
+		$found_rows = '';
+		if ( ! $this->query_vars['no_found_rows'] && ! empty( $limits ) ) {
+			$found_rows = 'SQL_CALC_FOUND_ROWS';
+		}
+
+		$this->request = "SELECT $found_rows $fields FROM $wpdb->comments $join $where $groupby $orderby $limits";
+
 		if ( $this->query_vars['count'] ) {
 			return $wpdb->get_var( $this->request );
 		}
@@ -679,6 +729,8 @@
 
 		if ( 'ids' == $this->query_vars['fields'] ) {
 			$this->comments = $wpdb->get_col( $this->request );
+			$this->comment_count = count( $this->comments );
+			$this->set_found_comments( $limits );
 			return array_map( 'intval', $this->comments );
 		}
 
@@ -702,6 +754,8 @@
 		}
 
 		$this->comments = $comments;
+		$this->comment_count = count( $this->comments );
+		$this->set_found_comments( $limits );
 		return $this->comments;
 	}
 
@@ -814,4 +868,42 @@
 			return 'DESC';
 		}
 	}
+
+	protected function set_found_comments( $limits ) {
+		global $wpdb;
+
+		// Bail if comments is an empty array.
+		if ( $this->query_vars['no_found_rows'] || empty( $this->comments ) ) {
+			return;
+		}
+
+		if ( ! empty( $limits ) ) {
+			/**
+			 * Filter the query to run for retrieving the found comments.
+			 *
+			 * @since 4.4.0
+			 *
+			 * @param string           $found_comments The query to run to find the found comments.
+			 * @param WP_Comment_Query $this           The WP_Comment_Query instance.
+			 */
+			$found_comments_query = apply_filters( 'found_comments_query', 'SELECT FOUND_ROWS()', $this );
+			$this->found_comments = $wpdb->get_var( $found_comments_query );
+		} else {
+			$this->found_comments = count( $this->comments );
+		}
+
+		/**
+		 * Filter the number of found comments for the query.
+		 *
+		 * @since 4.4.0
+		 *
+		 * @param int              $found_comments The number of comments found.
+		 * @param WP_Comment_Query $this           The WP_Comment_Query instance.
+		 */
+		$this->found_comments = apply_filters( 'found_comments', $this->found_comments, $this );
+
+		if ( ! empty( $limits ) ) {
+			$this->max_num_pages = ceil( $this->found_comments / $this->query_vars['number'] );
+		}
+	}
 }
Index: src/wp-includes/comment-template.php
===================================================================
--- src/wp-includes/comment-template.php	(revision 34267)
+++ src/wp-includes/comment-template.php	(working copy)
@@ -1208,6 +1208,7 @@
 
 	$comment_args = array(
 		'order'   => 'ASC',
+		'fields'  => 'ids',
 		'orderby' => 'comment_date_gmt',
 		'status'  => 'approve',
 		'post_id' => $post->ID,
@@ -1219,6 +1220,76 @@
 		$comment_args['include_unapproved'] = array( $comment_author_email );
 	}
 
+	$per_page = (int) get_query_var( 'comments_per_page' );
+	if ( 0 === $per_page ) {
+		$per_page = (int) get_option( 'comments_per_page' );
+	}
+
+	$threshold = $per_page ? $per_page * 2 : 100;
+	/**
+	 * Filter the threshold at which to force paging
+	 *
+	 * @since 4.4.0
+	 *
+	 * @param int     $threshold Number of comments on a post before forcing paging.
+	 * @param WP_Post $post      The WP_Post instance.
+	 */
+	$paging_threshold = apply_filters( 'force_comment_paging_threshold', $threshold, $post );
+
+	if ( (int) get_option( 'page_comments' ) || $post->comment_count > $paging_threshold ) {
+		add_filter( 'pre_option_page_comments', '__return_true' );
+
+		if ( $per_page ) {
+			$comment_args['number'] = $per_page;
+		} else {
+			$comment_args['number'] = $paging_threshold / 2;
+		}
+		$page = (int) get_query_var( 'cpage' );
+		if ( $page ) {
+			$comment_args['offset'] = ( $page - 1 ) * $per_page;
+		}
+	}
+
+	$threaded = get_option( 'thread_comments' );
+	if ( $threaded ) {
+		$comment_args['parent'] = 0;
+		// array of all top-level comment IDs for the post
+		$comment_query = new WP_Comment_Query( $comment_args );
+		$top_level = $comment_query->found_comments;
+		$comment_ids = $comment_query->comments;
+	} else {
+		$top_level = 0;
+		// array of all comment IDs for the post
+		$comment_ids = get_comments( $comment_args );
+	}
+
+	$wp_query->max_num_comment_pages = $comment_query->max_num_pages;
+
+	unset(
+		$comment_args['number'],
+		$comment_args['offset'],
+		$comment_args['parent']
+	);
+
+	if ( $comment_query->max_num_pages > 1 && $threaded ) {
+		$threaded_ids = array();
+		$args = $comment_args;
+
+		do {
+			$threaded_ids = array_merge( $threaded_ids, $comment_ids );
+			$args['parent__in'] = $comment_ids;
+			$comment_ids = get_comments( $args );
+		} while ( count( $comment_ids ) );
+
+		$comment_ids = $threaded_ids;
+	}
+
+	$comment_args['comment__in'] = $comment_ids;
+	$comment_args['orderby'] = 'comment__in';
+	unset(
+		$comment_args['order'],
+		$comment_args['fields']
+	);
 	$comments = get_comments( $comment_args );
 
 	/**
@@ -1849,6 +1920,10 @@
 	if ( null === $r['reverse_top_level'] )
 		$r['reverse_top_level'] = ( 'desc' == get_option('comment_order') );
 
+	if ( null === $comments && 1 < $wp_query->max_num_comment_pages ) {
+		$r['page'] = 1;
+	}
+
 	if ( empty( $r['walker'] ) ) {
 		$walker = new Walker_Comment;
 	} else {
