diff --git a/core/modules/comment/comment.admin.inc b/core/modules/comment/comment.admin.inc
index 6502873..3de484c 100644
--- a/core/modules/comment/comment.admin.inc
+++ b/core/modules/comment/comment.admin.inc
@@ -41,7 +41,6 @@ function comment_admin($type = 'new') {
  * @see comment_admin()
  * @see comment_admin_overview_validate()
  * @see comment_admin_overview_submit()
- * @see theme_comment_admin_overview()
  */
 function comment_admin_overview($form, &$form_state, $arg) {
   // Build an 'Update options' form.
diff --git a/core/modules/comment/comment.module b/core/modules/comment/comment.module
index cb62bea..42bbbe3 100644
--- a/core/modules/comment/comment.module
+++ b/core/modules/comment/comment.module
@@ -159,18 +159,13 @@ function comment_field_extra_fields() {
 function comment_theme() {
   return array(
     'comment_block' => array(
+      'template' => 'comment-block',
       'variables' => array('number' => NULL),
     ),
-    'comment_preview' => array(
-      'variables' => array('comment' => NULL),
-    ),
     'comment' => array(
       'template' => 'comment',
       'render element' => 'elements',
     ),
-    'comment_post_forbidden' => array(
-      'variables' => array('node' => NULL),
-    ),
     'comment_wrapper' => array(
       'template' => 'comment-wrapper',
       'render element' => 'content',
@@ -472,30 +467,6 @@ function comment_new_page_count($num_comments, $new_replies, EntityInterface $no
 }
 
 /**
- * Returns HTML for a list of recent comments.
- *
- * @ingroup themeable
- */
-function theme_comment_block($variables) {
-  $items = array();
-  $number = $variables['number'];
-  foreach (comment_get_recent($number) as $comment) {
-    $items[] = l($comment->subject, 'comment/' . $comment->cid, array('fragment' => 'comment-' . $comment->cid)) . '&nbsp;<span>' . t('@time ago', array('@time' => format_interval(REQUEST_TIME - $comment->changed))) . '</span>';
-  }
-
-  if ($items) {
-    $item_list = array(
-      '#theme' => 'item_list',
-      '#items' => $items,
-    );
-    return drupal_render($item_list);
-  }
-  else {
-    return t('No comments available.');
-  }
-}
-
-/**
  * Implements hook_node_view().
  */
 function comment_node_view(EntityInterface $node, EntityDisplay $display, $view_mode) {
@@ -550,12 +521,8 @@ function comment_node_view(EntityInterface $node, EntityDisplay $display, $view_
           }
         }
         else {
-          $comment_post_forbidden = array(
-            '#theme' => 'comment_post_forbidden',
-            '#node' => $node,
-          );
           $links['comment-forbidden'] = array(
-            'title' => drupal_render($comment_post_forbidden),
+            'title' => comment_forbidden_message($node),
             'html' => TRUE,
           );
         }
@@ -584,12 +551,8 @@ function comment_node_view(EntityInterface $node, EntityDisplay $display, $view_
           }
         }
         else {
-          $comment_post_forbidden = array(
-            '#theme' => 'comment_post_forbidden',
-            '#node' => $node,
-          );
           $links['comment-forbidden'] = array(
-            'title' => drupal_render($comment_post_forbidden),
+            'title' => comment_forbidden_message($node),
             'html' => TRUE,
           );
         }
@@ -893,11 +856,7 @@ function comment_links(Comment $comment, EntityInterface $node) {
       );
     }
     if (empty($links)) {
-      $comment_post_forbidden = array(
-        '#theme' => 'comment_post_forbidden',
-        '#node' => $node,
-      );
-      $links['comment-forbidden']['title'] = drupal_render($comment_post_forbidden);
+      $links['comment-forbidden']['title'] = comment_forbidden_message($node);
       $links['comment-forbidden']['html'] = TRUE;
     }
   }
@@ -1477,7 +1436,29 @@ function comment_prepare_author(Comment $comment) {
 }
 
 /**
- * Prepares variables for comment templates.
+ * Prepares variables for comment block templates.
+ *
+ * Default template: comment-block.html.twig.
+ *
+ * @param array $variables
+ *   An associative array containing:
+ *   - number: The number of recent comments to display.
+ */
+function template_preprocess_comment_block(&$variables) {
+  $items = array();
+  foreach (comment_get_recent($variables['number']) as $comment) {
+    $items[] = l($comment->subject, 'comment/' . $comment->cid, array('fragment' => 'comment-' . $comment->cid)) . '&nbsp;<span>' . t('@time ago', array('@time' => format_interval(REQUEST_TIME - $comment->changed))) . '</span>';
+  }
+  if (!empty($items)) {
+    $variables['comments'] = array(
+      '#theme' => 'item_list',
+      '#items' => $items,
+    );
+  }
+}
+
+/**
+ * Preprocesses variables for comment.tpl.php.
  *
  * Default template: comment.html.twig.
  *
@@ -1609,50 +1590,49 @@ function template_preprocess_comment(&$variables) {
 }
 
 /**
- * Returns HTML for a "you can't post comments" notice.
- *
- * @param $variables
- *   An associative array containing:
- *   - node: The comment node.
- *
- * @ingroup themeable
- */
-function theme_comment_post_forbidden($variables) {
-  $node = $variables['node'];
+  * Provides a message if posting comments is forbidden.
+  *
+  * If authenticated users can post comments, a message is returned that prompts
+  * the anonymous user to log in (or register, if applicable) that redirects to
+  * node comment form. Otherwise, no message is returned.
+  *
+  * @param \Drupal\Core\Entity\EntityInterface $node
+  *   The node the comment is attached to.
+  */
+function comment_forbidden_message(EntityInterface $node) {
   global $user;
 
+  // Whether the user will be able to post comments once logged in.
   // Since this is expensive to compute, we cache it so that a page with many
   // comments only has to query the database once for all the links.
-  $authenticated_post_comments = &drupal_static(__FUNCTION__, NULL);
-
-  if ($user->isAnonymous()) {
-    if (!isset($authenticated_post_comments)) {
-      // We only output a link if we are certain that users will get permission
-      // to post comments by logging in.
-      $comment_roles = user_roles(TRUE, 'post comments');
-      $authenticated_post_comments = isset($comment_roles[DRUPAL_AUTHENTICATED_RID]);
-    }
-
-    if ($authenticated_post_comments) {
-      // We cannot use drupal_get_destination() because these links
-      // sometimes appear on /node and taxonomy listing pages.
-      if (variable_get('comment_form_location_' . $node->getType(), COMMENT_FORM_BELOW) == COMMENT_FORM_SEPARATE_PAGE) {
-        $destination = array('destination' => 'comment/reply/' . $node->id() . '#comment-form');
-      }
-      else {
-        $destination = array('destination' => 'node/' . $node->id() . '#comment-form');
-      }
+  $auth_post_comments = &drupal_static(__FUNCTION__, NULL);
+  if (!isset($auth_post_comments)) {
+    $comment_roles = user_roles(TRUE, 'post comments');
+    $auth_post_comments = isset($comment_roles[DRUPAL_AUTHENTICATED_RID]);
+  }
 
-      if (\Drupal::config('user.settings')->get('register') != USER_REGISTER_ADMINISTRATORS_ONLY) {
-        // Users can register themselves.
-        return t('<a href="@login">Log in</a> or <a href="@register">register</a> to post comments', array('@login' => url('user/login', array('query' => $destination)), '@register' => url('user/register', array('query' => $destination))));
-      }
-      else {
-        // Only admins can add new users, no public registration.
-        return t('<a href="@login">Log in</a> to post comments', array('@login' => url('user/login', array('query' => $destination))));
-      }
+  if (!user_is_logged_in() && $auth_post_comments) {
+    // Build login and register links. We cannot use drupal_get_destination()
+    // because these links sometimes appear on /node and taxonomy listing pages.
+    if (variable_get('comment_form_location_' . $node->type, COMMENT_FORM_BELOW) == COMMENT_FORM_SEPARATE_PAGE) {
+      $destination = array('destination' => "comment/reply/$node->nid#comment-form");
+    }
+    else {
+      $destination = array('destination' => "node/$node->nid#comment-form");
+    }
+    // Message depends on whether users may register accounts.
+    if (config('user.settings')->get('register') != USER_REGISTER_ADMINISTRATORS_ONLY) {
+      $message = t('<a href="@login">Log in</a> or <a href="@register">register</a> to post comments', array('@login' => url('user/login', array('query' => $destination)), '@register' => url('user/register', array('query' => $destination))));
+    }
+    else {
+      $message = t('<a href="@login">Log in</a> to post comments', array('@login' => url('user/login', array('query' => $destination))));
     }
   }
+  else {
+    $message = '';
+  }
+
+  return $message;
 }
 
 /**
diff --git a/core/modules/comment/lib/Drupal/comment/Tests/CommentLinksTest.php b/core/modules/comment/lib/Drupal/comment/Tests/CommentLinksTest.php
index 7bb0458..46301cf 100644
--- a/core/modules/comment/lib/Drupal/comment/Tests/CommentLinksTest.php
+++ b/core/modules/comment/lib/Drupal/comment/Tests/CommentLinksTest.php
@@ -259,7 +259,7 @@ function assertCommentLinks(array $info) {
 
         // Anonymous users should see a note to log in or register in case
         // authenticated users are allowed to post comments.
-        // @see theme_comment_post_forbidden()
+        // @see comment-post-forbidden.html.twig
         if (!$this->loggedInUser) {
           if (user_access('post comments', $this->web_user)) {
             // The note depends on whether users are actually able to register.
diff --git a/core/modules/comment/templates/comment-block.html.twig b/core/modules/comment/templates/comment-block.html.twig
new file mode 100644
index 0000000..65b7249
--- /dev/null
+++ b/core/modules/comment/templates/comment-block.html.twig
@@ -0,0 +1,18 @@
+{#
+/**
+ * @file
+ * Default theme implementation for a list of recent comments.
+ *
+ * Available variables:
+ * - comments: A list of recent comments.
+ *
+ * @see template_preprocess_comment_block()
+ *
+ * @ingroup themeable
+ */
+#}
+{% if not comments %}
+  {{ 'No comments available.'|t }}
+{% else %}
+  {{ comments }}
+{% endif %}
