diff --git a/core/includes/common.inc b/core/includes/common.inc
index 5a90646..d59c936 100644
--- a/core/includes/common.inc
+++ b/core/includes/common.inc
@@ -2809,6 +2809,17 @@ function drupal_render(&$elements, $is_recursive_call = FALSE) {
     $current->postRenderCache = NestedArray::mergeDeep($current->postRenderCache, $parent->postRenderCache);
     $stack->push($current);
   };
+  /** @var \Drupal\Core\Controller\ControllerResolverInterface $controller_resolver */
+  $controller_resolver = \Drupal::service('controller_resolver');
+  if (isset($elements['#access_callback'])) {
+    if (is_string($elements['#access_callback']) && strpos($elements['#access_callback'], '::') === FALSE) {
+      $callable = $controller_resolver->getControllerFromDefinition($elements['#access_callback']);
+    }
+    else {
+      $callable = $elements['#access_callback'];
+    }
+    $elements['#access'] = call_user_func($callable, $elements);
+  }
 
   // Early-return nothing if user does not have access.
   if (empty($elements) || (isset($elements['#access']) && !$elements['#access'])) {
@@ -2856,8 +2867,6 @@ function drupal_render(&$elements, $is_recursive_call = FALSE) {
   // Make any final changes to the element before it is rendered. This means
   // that the $element or the children can be altered or corrected before the
   // element is rendered into the final text.
-  /** @var \Drupal\Core\Controller\ControllerResolverInterface $controller_resolver */
-  $controller_resolver = \Drupal::service('controller_resolver');
   if (isset($elements['#pre_render'])) {
     foreach ($elements['#pre_render'] as $callable) {
       if (is_string($callable) && strpos($callable, '::') === FALSE) {
diff --git a/core/lib/Drupal/Core/Access/AccessManagerInterface.php b/core/lib/Drupal/Core/Access/AccessManagerInterface.php
index df88ba6..1f8fc6d 100644
--- a/core/lib/Drupal/Core/Access/AccessManagerInterface.php
+++ b/core/lib/Drupal/Core/Access/AccessManagerInterface.php
@@ -45,7 +45,7 @@
    * @param array $parameters
    *   Optional array of values to substitute into the route path patern.
    * @param \Drupal\Core\Session\AccountInterface $account
-   *   The current user.
+   *   Run access checks for this account. Defaults to the current user.
    * @param \Symfony\Component\HttpFoundation\Request $route_request
    *   Optional incoming request object. If not provided, one will be built
    *   using the route information and the current request from the container.
diff --git a/core/lib/Drupal/Core/Routing/CurrentRouteMatch.php b/core/lib/Drupal/Core/Routing/CurrentRouteMatch.php
index 4b482ea..7971285 100644
--- a/core/lib/Drupal/Core/Routing/CurrentRouteMatch.php
+++ b/core/lib/Drupal/Core/Routing/CurrentRouteMatch.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\Core\Routing;
 
+use Drupal\Core\Session\AccountInterface;
 use Symfony\Component\HttpFoundation\Request;
 use Symfony\Component\HttpFoundation\RequestStack;
 
@@ -92,6 +93,21 @@ public function getCurrentRouteMatch() {
     return $this->getRouteMatch($this->requestStack->getCurrentRequest());
   }
 
+
+  /**
+   * {@inheritdoc}
+   */
+  public function access(AccountInterface $account = NULL) {
+    return $this->getCurrentRouteMatch()->access($account);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function createUrlObject(array $options = array()) {
+    return $this->getCurrentRouteMatch()->createUrlObject($options);
+  }
+
   /**
    * Returns the route match for a passed in request.
    *
diff --git a/core/lib/Drupal/Core/Routing/NullRouteMatch.php b/core/lib/Drupal/Core/Routing/NullRouteMatch.php
index 0ef2c3b..adcf936 100644
--- a/core/lib/Drupal/Core/Routing/NullRouteMatch.php
+++ b/core/lib/Drupal/Core/Routing/NullRouteMatch.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\Core\Routing;
 
+use Drupal\Core\Session\AccountInterface;
 use Symfony\Component\HttpFoundation\ParameterBag;
 
 /**
@@ -56,4 +57,17 @@ public function getRawParameters() {
     return new ParameterBag();
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  public function access(AccountInterface $account = NULL) {
+    return FALSE;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function createUrlObject(array $options = array()) {
+    return NULL;
+  }
 }
diff --git a/core/lib/Drupal/Core/Routing/RouteMatch.php b/core/lib/Drupal/Core/Routing/RouteMatch.php
index eafb184..8b29958 100644
--- a/core/lib/Drupal/Core/Routing/RouteMatch.php
+++ b/core/lib/Drupal/Core/Routing/RouteMatch.php
@@ -7,6 +7,9 @@
 
 namespace Drupal\Core\Routing;
 
+use Drupal\Core\Access\AccessManagerInterface;
+use Drupal\Core\Session\AccountInterface;
+use Drupal\Core\Url;
 use Symfony\Cmf\Component\Routing\RouteObjectInterface;
 use Symfony\Component\HttpFoundation\ParameterBag;
 use Symfony\Component\HttpFoundation\Request;
@@ -46,6 +49,13 @@ class RouteMatch implements RouteMatchInterface {
   protected $rawParameters;
 
   /**
+   * The access manager.
+   *
+   * @var \Drupal\Core\Access\AccessManagerInterface
+   */
+  protected $accessManager;
+
+  /**
    * Constructs a RouteMatch object.
    *
    * @param string $route_name
@@ -140,6 +150,41 @@ public function getRawParameters() {
   }
 
   /**
+   * {@inheritdoc}
+   */
+  public function createUrlObject(array $options = array()) {
+    return new Url($this->getRouteName(), $this->getRawParameters()->all(), $options);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function access(AccountInterface $account = NULL) {
+    return $this->getAccessManager()->checkNamedRoute($this->getRouteName(), $this->getRawParameters()->all(), $account);
+  }
+
+  /**
+   * Gets the access manager.
+   *
+   * @return \Drupal\Core\Access\AccessManagerInterface
+   */
+  protected function getAccessManager() {
+    if (!isset($this->accessManager)) {
+      $this->accessManager = \Drupal::service('access_manager');
+    }
+    return $this->accessManager;
+  }
+
+  /**
+   * Sets the access manager.
+   *
+   * @param \Drupal\Core\Access\AccessManagerInterface $access_manager
+   */
+  public function setAccessManager(AccessManagerInterface $access_manager) {
+    $this->accessManager = $access_manager;
+  }
+
+  /**
    * Returns the names of all parameters for the currently matched route.
    *
    * @return array
diff --git a/core/lib/Drupal/Core/Routing/RouteMatchInterface.php b/core/lib/Drupal/Core/Routing/RouteMatchInterface.php
index f0d9aa8..35944f8 100644
--- a/core/lib/Drupal/Core/Routing/RouteMatchInterface.php
+++ b/core/lib/Drupal/Core/Routing/RouteMatchInterface.php
@@ -7,6 +7,8 @@
 
 namespace Drupal\Core\Routing;
 
+use Drupal\Core\Session\AccountInterface;
+
 /**
  * Provides an interface for classes representing the result of routing.
  *
@@ -79,4 +81,43 @@ public function getRawParameter($parameter_name);
    */
   public function getRawParameters();
 
+  /**
+   * Checks a route match object with against applicable access check services.
+   *
+   * Determines whether the route is accessible or not.
+   *
+   * @param \Drupal\Core\Session\AccountInterface $account
+   *   Run access checks for this account. Defaults to the current user.
+   *
+   * @return bool
+   *   Returns TRUE if the user has access to the route, otherwise FALSE.
+   */
+  public function access(AccountInterface $account = NULL);
+
+  /**
+   * Creates a Url object from this route match.
+   *
+   * @param array $options
+   *   (optional) An associative array of additional options, with the following
+   *   elements:
+   *   - 'query': An array of query key/value-pairs (without any URL-encoding)
+   *     to append to the URL. Merged with the parameters array.
+   *   - 'fragment': A fragment identifier (named anchor) to append to the URL.
+   *     Do not include the leading '#' character.
+   *   - 'absolute': Defaults to FALSE. Whether to force the output to be an
+   *     absolute link (beginning with http:). Useful for links that will be
+   *     displayed outside the site, such as in an RSS feed.
+   *   - 'language': An optional language object used to look up the alias
+   *     for the URL. If $options['language'] is omitted, it defaults to the
+   *     current language for the language type LanguageInterface::TYPE_URL.
+   *   - 'https': Whether this URL should point to a secure location. If not
+   *     defined, the current scheme is used, so the user stays on HTTP or HTTPS
+   *     respectively. if mixed mode sessions are permitted, TRUE enforces HTTPS
+   *     and FALSE enforces HTTP.
+   *
+   * @return \Drupal\Core\Url|NULL
+   *   The url object. NULL if no route is matched.
+   */
+  public function createUrlObject(array $options = array());
+
 }
diff --git a/core/lib/Drupal/Core/Url.php b/core/lib/Drupal/Core/Url.php
index ea407cc..e8eb800 100644
--- a/core/lib/Drupal/Core/Url.php
+++ b/core/lib/Drupal/Core/Url.php
@@ -8,8 +8,10 @@
 namespace Drupal\Core;
 
 use Drupal\Component\Utility\UrlHelper;
+use Drupal\Core\Access\AccessManagerInterface;
 use Drupal\Core\DependencyInjection\DependencySerializationTrait;
 use Drupal\Core\Routing\UrlGeneratorInterface;
+use Drupal\Core\Session\AccountInterface;
 use Symfony\Cmf\Component\Routing\RouteObjectInterface;
 use Symfony\Component\HttpFoundation\Request;
 
@@ -386,6 +388,7 @@ public function toRenderArray() {
         '#route_name' => $this->getRouteName(),
         '#route_parameters' => $this->getRouteParameters(),
         '#options' => $this->getOptions(),
+        '#access_callback' => array(get_class(), 'renderAccess'),
       );
     }
   }
@@ -412,6 +415,53 @@ public function getInternalPath() {
   }
 
   /**
+   * Checks this Url object against applicable access check services.
+   *
+   * Determines whether the route is accessible or not.
+   *
+   * @param \Drupal\Core\Session\AccountInterface $account
+   *   Run access checks for this account. Defaults to the current user.
+   *
+   * @return bool
+   *   Returns TRUE if the user has access to the url, otherwise FALSE.
+   */
+  public function access(AccountInterface $account = NULL) {
+    return $account->hasPermission('link to any page') || $this->accessManager()->checkNamedRoute($this->getRouteName(), $this->getRouteParameters(), $account);
+  }
+
+  /**
+   * Checks a Url render element against applicable access check services.
+   *
+   * @param array $element
+   *   A render element as returned from \Drupal\Core\Url::toRenderArray().
+   *
+   * @return bool
+   *   Returns TRUE if the current user has access to the url, otherwise FALSE.
+   */
+  public static function renderAccess(array $element) {
+    return (new static($element['#route_name'], $element['#route_parameters'], $element['#options']))->access();
+  }
+
+  /**
+   * @return \Drupal\Core\Access\AccessManagerInterface
+   */
+  protected function accessManager() {
+    if (!isset($this->accessManager)) {
+      $this->accessManager = \Drupal::service('access_manager');
+    }
+    return $this->accessManager;
+  }
+
+  /**
+   * Sets the access manager.
+   *
+   * @param \Drupal\Core\Access\AccessManagerInterface $access_manager
+   */
+  public function setAccessManager(AccessManagerInterface $access_manager) {
+    $this->accessManager = $access_manager;
+  }
+
+  /**
    * Gets the URL generator.
    *
    * @return \Drupal\Core\Routing\UrlGeneratorInterface
diff --git a/core/modules/system/src/Plugin/Block/SystemBrandingBlock.php b/core/modules/system/src/Plugin/Block/SystemBrandingBlock.php
index 77e63e1..d9abc4d 100644
--- a/core/modules/system/src/Plugin/Block/SystemBrandingBlock.php
+++ b/core/modules/system/src/Plugin/Block/SystemBrandingBlock.php
@@ -15,6 +15,7 @@
 use Drupal\Core\Routing\UrlGeneratorInterface;
 use Drupal\Core\Session\AccountInterface;
 use Drupal\Component\Utility\Xss;
+use Drupal\Core\Url;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
@@ -111,26 +112,26 @@ public function blockForm($form, FormStateInterface $form_state) {
     $theme = $form_state['block_theme'];
 
     // Get permissions.
-    $administer_themes_access = $this->currentUser->hasPermission('administer themes');
-    $administer_site_configuration_access = $this->currentUser->hasPermission('administer site configuration');
-
-    if ($administer_themes_access) {
-      // Get paths to theme settings pages.
-      $appearance_settings_url = $this->urlGenerator->generateFromRoute('system.theme_settings');
-      $theme_settings_url = $this->urlGenerator->generateFromRoute('system.theme_settings_theme', array('theme' => $theme));
+    $url_system_theme_settings = new Url('system.theme_settings');
+    $url_system_theme_settings_theme = new Url('system.theme_settings_theme', array('theme' => $theme));
 
+    if ($url_system_theme_settings->access() && $url_system_theme_settings_theme->access()) {
       // Provide links to the Appearance Settings and Theme Settings pages
       // if the user has access to administer themes.
-      $site_logo_description = $this->t('Defined on the <a href="@appearance">Appearance Settings</a> or <a href="@theme">Theme Settings</a> page.', array('@appearance' => $appearance_settings_url, '@theme' => $theme_settings_url));
+      $site_logo_description = $this->t('Defined on the <a href="@appearance">Appearance Settings</a> or <a href="@theme">Theme Settings</a> page.', array(
+        '@appearance' => $url_system_theme_settings->toString(),
+        '@theme' => $url_system_theme_settings_theme->toString(),
+      ));
     }
     else {
       // Explain that the user does not have access to the Appearance and Theme
       // Settings pages.
       $site_logo_description = $this->t('Defined on the Appearance or Theme Settings page. You do not have the appropriate permissions to change the site logo.');
     }
-    if ($administer_site_configuration_access) {
+    $url_system_site_information_settings = new Url('system.site_information_settings');
+    if ($url_system_site_information_settings->access()) {
       // Get paths to settings pages.
-      $site_information_url = $this->urlGenerator->generateFromRoute('system.site_information_settings');
+      $site_information_url = $url_system_site_information_settings->toString();
 
       // Provide link to Site Information page if the user has access to
       // administer site configuration.
diff --git a/core/modules/system/src/Tests/Routing/UrlIntegrationTest.php b/core/modules/system/src/Tests/Routing/UrlIntegrationTest.php
new file mode 100644
index 0000000..66239c9
--- /dev/null
+++ b/core/modules/system/src/Tests/Routing/UrlIntegrationTest.php
@@ -0,0 +1,68 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\system\Tests\Routing\UrlIntegrationTest.
+ */
+
+namespace Drupal\system\Tests\Routing;
+
+use Drupal\Core\Url;
+use Drupal\simpletest\KernelTestBase;
+use Drupal\user\Entity\Role;
+use Drupal\user\Entity\User;
+
+/**
+ * Tests the URL object integration into the access system.
+ *
+ * @group Url
+ */
+class UrlIntegrationTest extends KernelTestBase {
+
+  /**
+   * Modules to enable.
+   *
+   * @var array
+   */
+  public static $modules = array('user', 'router_test', 'system');
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp() {
+    parent::setUp();
+
+    $this->installSchema('system', ['router']);
+  }
+
+  /**
+   * Ensures that the access() method on \Drupal\Core\Url objects works.
+   */
+  public function testAccess() {
+    \Drupal::service('router.builder')->rebuild();
+    /** @var \Drupal\user\RoleInterface $role_with_access */
+    $role_with_access = Role::create(['id' => 'role_with_access']);
+    $role_with_access->grantPermission('administer users');
+    $role_with_access->save();
+
+    /** @var \Drupal\user\RoleInterface $role_without_access */
+    $role_without_access = Role::create(['id' => 'role_without_access']);
+    $role_without_access->save();
+
+    $user_with_access = User::create(['roles' => ['role_with_access']]);
+    $user_without_access = User::create(['roles' => ['role_without_access']]);
+
+    $url_always_access = new Url('router_test.1');
+    $this->assertTrue($url_always_access->access($user_with_access));
+    $this->assertTrue($url_always_access->access($user_without_access));
+
+    $url_none_access = new Url('router_test.15');
+    $this->assertFalse($url_none_access->access($user_with_access));
+    $this->assertFalse($url_none_access->access($user_without_access));
+
+    $url_access = new Url('router_test.16');
+    $this->assertTrue($url_access->access($user_with_access));
+    $this->assertFalse($url_access->access($user_without_access));
+  }
+
+}
diff --git a/core/modules/system/tests/modules/router_test_directory/router_test.routing.yml b/core/modules/system/tests/modules/router_test_directory/router_test.routing.yml
index 7405d88..5b02a3b 100644
--- a/core/modules/system/tests/modules/router_test_directory/router_test.routing.yml
+++ b/core/modules/system/tests/modules/router_test_directory/router_test.routing.yml
@@ -93,6 +93,20 @@ router_test.14:
   defaults:
     _controller: '\Drupal\router_test\TestControllers::test9'
 
+router_test.15:
+  path: '/router_test/test15'
+  defaults:
+    _controller: '\Drupal\router_test\TestControllers::test1'
+  requirements:
+    _access: 'FALSE'
+
+router_test.16:
+  path: '/router_test/test16'
+  defaults:
+    _controller: '\Drupal\router_test\TestControllers::test1'
+  requirements:
+    _permission: 'administer users'
+
 router_test.hierarchy_parent:
   path: '/menu-test/parent'
   defaults:
diff --git a/core/modules/user/user.module b/core/modules/user/user.module
index 75777bb..21c5615 100644
--- a/core/modules/user/user.module
+++ b/core/modules/user/user.module
@@ -1101,6 +1101,10 @@ function user_user_role_insert(RoleInterface $role) {
   }
 
   $add_id = 'user_add_role_action.' . $role->id();
+
+  if (!\Drupal::entityManager()->hasDefinition('action')) {
+    return;
+  }
   if (!entity_load('action', $add_id)) {
     $action = entity_create('action', array(
       'id' => $add_id,
diff --git a/core/tests/Drupal/Tests/Core/Routing/RouteMatchTest.php b/core/tests/Drupal/Tests/Core/Routing/RouteMatchTest.php
index 6aab6f4..6289409 100644
--- a/core/tests/Drupal/Tests/Core/Routing/RouteMatchTest.php
+++ b/core/tests/Drupal/Tests/Core/Routing/RouteMatchTest.php
@@ -65,4 +65,42 @@ public function testRouteMatchFromRequest() {
     $this->assertSame(array('foo' => '1'), $route_match->getRawParameters()->all());
   }
 
+  /**
+   * Tests the access() method.
+   *
+   * @covers ::access
+   * @covers ::getAccessManager
+   * @covers ::setAccessManager
+   */
+  public function testAccess() {
+    foreach ([TRUE, FALSE] as $access) {
+      $account = $this->getMock('Drupal\Core\Session\AccountInterface');
+
+      $access_manager = $this->getMock('Drupal\Core\Access\AccessManagerInterface');
+      $access_manager->expects($this->once())
+        ->method('checkNamedRoute')
+        ->with('entity.node.canonical', ['node' => 3], $account)
+        ->willReturn($access);
+
+      $route_match = new RouteMatch('entity.node.canonical', new Route('node/{node}'), ['node' => (object) ['nid' => 3]], ['node' => 3]);
+      $route_match->setAccessManager($access_manager);
+
+      $this->assertEquals($access, $route_match->access($account));
+    }
+  }
+
+  /**
+   * Tests the createUrlObject() method.
+   *
+   * @covers ::createUrlObject
+   */
+  public function testCreateUrlObject() {
+    $route_match = new RouteMatch('entity.node.canonical', new Route('node/{node}'), ['node' => (object) ['nid' => 3]], ['node' => 3]);
+
+    $url = $route_match->createUrlObject(['foo' => 'bar']);
+    $this->assertEquals('entity.node.canonical', $url->getRouteName());
+    $this->assertEquals(['node' => 3], $url->getRouteParameters());;
+    $this->assertEquals(['foo' => 'bar'], $url->getOptions());
+  }
+
 }
diff --git a/core/tests/Drupal/Tests/Core/UrlTest.php b/core/tests/Drupal/Tests/Core/UrlTest.php
index 92f429d..9f3850a 100644
--- a/core/tests/Drupal/Tests/Core/UrlTest.php
+++ b/core/tests/Drupal/Tests/Core/UrlTest.php
@@ -318,4 +318,28 @@ public function testGetOptions($urls) {
     }
   }
 
+  /**
+   * Tests the access() method.
+   *
+   * @covers ::access
+   * @covers ::getAccessManager
+   * @covers ::setAccessManager
+   */
+  public function testAccess() {
+    foreach ([FALSE, TRUE] as $access) {
+      $account = $this->getMock('Drupal\Core\Session\AccountInterface');
+
+      $access_manager = $this->getMock('Drupal\Core\Access\AccessManagerInterface');
+      $access_manager->expects($this->once())
+        ->method('checkNamedRoute')
+        ->with('entity.node.canonical', ['node' => 3], $account)
+        ->willReturn($access);
+
+      $url = new Url('entity.node.canonical', ['node' => 3]);
+      $url->setAccessManager($access_manager);
+
+      $this->assertEquals($access, $url->access($account));
+    }
+  }
+
 }
